溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

HBase原理——要弄懂的sequenceId

發(fā)布時(shí)間:2020-07-17 14:33:20 來源:網(wǎng)絡(luò) 閱讀:278 作者:Hjiangxue 欄目:大數(shù)據(jù)

為什么需要sequenceId?

HBase數(shù)據(jù)在寫入的時(shí)候首先追加寫入HLog,再寫入Memstore,也就是說一份數(shù)據(jù)會(huì)以兩種不同的形式存在于兩個(gè)地方。那兩個(gè)地方的同一份數(shù)據(jù)需不需要一種機(jī)制將兩者關(guān)聯(lián)起來?有的朋友要問為什么需要關(guān)聯(lián)這兩者,那筆者這里提出三個(gè)相關(guān)問題:

  1. Memstore中的數(shù)據(jù)flush到HDFS文件中后HLog對(duì)應(yīng)的數(shù)據(jù)是不是就可以被刪除了?不然HLog會(huì)無限增長!那問題來了,Memstore中被flush到HDFS的數(shù)據(jù),如何映射到HLog中的相關(guān)日志數(shù)據(jù)?

  2. HBase中單個(gè)HLog都有固定大小,日志文件最大個(gè)數(shù)也是固定設(shè)置的,默認(rèn)最大HLog文件數(shù)量為8。如果日志數(shù)量超過這個(gè)數(shù)量,就必須刪除最老的HLog日志。那問題來了,如何知道待刪除HLog日志對(duì)應(yīng)的所有數(shù)據(jù)都已經(jīng)落盤了?(如果知道哪些數(shù)據(jù)沒有落盤,就可以強(qiáng)制對(duì)其執(zhí)行flush,之后就可以將HLog刪除)

  3. RegionServer宕機(jī)之后Memstore中數(shù)據(jù)必然會(huì)丟失,大家都知道可以通過HLog進(jìn)行恢復(fù)。那問題來了,HLog中哪些數(shù)據(jù)需要恢復(fù)?哪些不需要恢復(fù)?

這三個(gè)問題從本質(zhì)上來講是一個(gè)問題,都需要一種介質(zhì)來表示Memstore中數(shù)據(jù)Flush的那個(gè)點(diǎn)對(duì)應(yīng)HLog哪個(gè)位置,這個(gè)介質(zhì)就是本文要介紹的重點(diǎn)-sequenceId

HLog日志核心結(jié)構(gòu)

要理解sequenceId,需要簡單了解HBase中HLog文件的基本結(jié)構(gòu),如下圖所示,關(guān)注點(diǎn)主要有兩點(diǎn):

HBase原理——要弄懂的sequenceId

  1. 每個(gè)RegionServer擁有一個(gè)或多個(gè)HLog(默認(rèn)只有1個(gè),1.x版本可以開啟 MultiWAL 功能,允許多個(gè)HLog)。 每個(gè)HLog是多個(gè)Region共享的 ,如圖所示,Region A、Region B和Region C共享一個(gè)HLog文件。

  2. HLog中日志單元WALEntry表示一次行級(jí)更新的最小追加單元(圖中紅色/×××小方框) ,它由兩部分組成:HLogKey和WALEdit,HLogKey中包含多個(gè)屬性信息,包含table name、region name、 sequenceid 等; WALEdit用來表示一個(gè)事務(wù)中的更新集合, 一次行級(jí)事務(wù)可以原子操作同一行中的多個(gè)列。上圖中WALEdit包含多個(gè)KeyValue。

什么是sequenceid?

sequenceid是region級(jí)別一次行級(jí)事務(wù)的自增序號(hào)。這個(gè)定義是我琢磨出來的,需要關(guān)注的地方有三個(gè):

  1. sequenceid是自增序號(hào)。很好理解,就是隨著時(shí)間推移不斷自增,不會(huì)減小。

  2. sequenceid是一次行級(jí)事務(wù)的自增序號(hào)。行級(jí)事務(wù)是什么?簡單點(diǎn)說,就是更新一行中的多個(gè)列族、多個(gè)列,行級(jí)事務(wù)能夠保證這次更新的原子性、一致性、持久性以及設(shè)置的隔離性,HBase會(huì)為一次行級(jí)事務(wù)分配一個(gè)自增序號(hào)。

  3. sequenceid是 region級(jí)別 的自增序號(hào)。每個(gè)region都維護(hù)屬于自己的sequenceid,不同region的sequenceid相互獨(dú)立。

在這樣的定義條件下,HLog就會(huì)如下圖所示:

HBase原理——要弄懂的sequenceId

HLog中有兩個(gè)Region的日志記錄,方框中的數(shù)字表示sequenceid,隨著時(shí)間的推移,每個(gè)region的sequenceid都獨(dú)立自增。

問題一:HLog在什么時(shí)候可以過期回收?

下圖中虛線右側(cè)部分為超過單個(gè)HLog大小閾值后切分形成的一個(gè)HLog文件,問題是這個(gè)文件什么時(shí)候可以被系統(tǒng)回收刪除。理論上來說只需要這個(gè)文件上所有Region對(duì)應(yīng)的最大sequenceid已經(jīng)落盤就可以刪除,比如下圖中如果RegionA對(duì)應(yīng)的最大sequenceid(5)已經(jīng)落盤,同時(shí)RegionB對(duì)應(yīng)的最大sequenceid(5)也落盤,那該HLog就可以被刪除。那怎么實(shí)現(xiàn)的呢?

HBase原理——要弄懂的sequenceId

RegionServer會(huì)為每個(gè)Region維護(hù)了一個(gè)變量oldestUnflushedSequenceId(實(shí)際上是為每個(gè)Store,為了方便講解,此處暫且認(rèn)為是Region,不影響原理),表示這個(gè)Region最早的還未落盤的seqid ,即這個(gè)seqid之前的所有數(shù)據(jù)都已經(jīng)落盤。接下來看看這個(gè)值在flush的時(shí)候是怎么維護(hù)的,以及如何用這個(gè)值實(shí)現(xiàn)HLog的過期回收判斷。

下圖是flush過程中oldestUnflushedSequenceId變量變化的示意圖,初始時(shí)為null,假設(shè)在某一時(shí)刻階段二RegionA(紅色方框)要執(zhí)行flush,中間HLog中sequenceId為1~4對(duì)應(yīng)的數(shù)據(jù)將會(huì)落盤,在執(zhí)行flush之前,HBase會(huì)append一個(gè)空的Entry到HLog,僅為獲取下一個(gè)sequenceId(5),并將這個(gè)sequenceId賦給OldestUnflushedSequenceId-RegionA。如圖中第三階段OldestUnflushedSequenceId-RegionA指向sequenceId為5的Entry。

HBase原理——要弄懂的sequenceId

可見,每次flush之后這個(gè)變量就會(huì)往前移動(dòng)一段距離。這個(gè)變量至關(guān)重要,是解決文初提到的三個(gè)問題的關(guān)鍵?;谏鲜鰧?duì)這個(gè)變量的理解,來看看下面兩種場景下右側(cè)HLog是否可以刪除:

HBase原理——要弄懂的sequenceId

很顯然,場景一中右側(cè)HLog還有未落盤的數(shù)據(jù)(sequenceid=5還未落盤),因此不能刪除;而場景二中右側(cè)HLog的所有數(shù)據(jù)都已經(jīng)落盤,所以這個(gè)HLog理論上就已經(jīng)可以被刪除回收。

問題二:HLog數(shù)量超過閾值(maxlogs)之后刪除最早HLog,應(yīng)該強(qiáng)制刷新哪些Region?

假設(shè)當(dāng)前系統(tǒng)設(shè)置了HLog的最大數(shù)量為32,即hbase.regionserver.maxlogs=32,上圖中最左側(cè)HLog是第33個(gè),此時(shí)系統(tǒng)會(huì)獲取到最老的日志(最右側(cè)HLog),并檢查所有的Entry對(duì)應(yīng)的數(shù)據(jù)是否都已經(jīng)落盤,如圖所示RegionC還有部分?jǐn)?shù)據(jù)沒有落地,為了安全刪除這個(gè)HLog就必須強(qiáng)制對(duì)該Region執(zhí)行flush操作,將所有數(shù)據(jù)落盤。
HBase原理——要弄懂的sequenceId

問題三:RegionServer宕機(jī)恢復(fù)replay日志時(shí)哪些WALEntry需要被回放,哪些會(huì)被skip?

理論上來說只需要回放Memstore中沒有落地的數(shù)據(jù)對(duì)應(yīng)的WALEntry,已經(jīng)落地?cái)?shù)據(jù)對(duì)應(yīng)的WALEntry可以skip??蓡栴}是RegionServer已經(jīng)宕機(jī)了, 對(duì)應(yīng)信息肯定沒有了,如何是好?想辦法持久化唄,上文分析oldestUnflushedSequenceId變量是flush時(shí)產(chǎn)生的一個(gè)變量,這個(gè)變量 完全 可以以flush的時(shí)候以元數(shù)據(jù)的形式寫到HFile中 (代碼見下圖):
HBase原理——要弄懂的sequenceId
這樣Region在宕機(jī)遷移重新打開之后加載HFile元數(shù)據(jù)就可以恢復(fù)出這個(gè)核心變量oldestUnflushedSequenceId(本次flush所生成的所有HFlie中都存儲(chǔ)同一個(gè)sequenceId),這個(gè)sequenceId在恢復(fù)出來之后就可以用來在回放WALEntry的時(shí)候過濾哪些Entry需要被回放,哪些會(huì)被skip。

這里提一個(gè)問題:有沒有可能一次flush所生成的所有HFile中存儲(chǔ)的sequenceId出現(xiàn)不一致,比如:region中所有store(store1、store2)都執(zhí)行flush,其中store1執(zhí)行flush成功,此時(shí)oldestUnflushedSequenceId變量成功追加到對(duì)應(yīng)的HFile中;但在store2執(zhí)行flush之前RegionServer發(fā)生宕機(jī)異常,store2對(duì)應(yīng)的oldestUnflushedSequenceId變量還是上個(gè)文件對(duì)應(yīng)的sequenceId,這種情況下回放數(shù)據(jù)會(huì)不會(huì)有影響?如果有,為什么?如果沒有,是什么機(jī)制保證的?

到目前為止,上面所有分析都基于一個(gè)事實(shí):hbase中flush操作是region級(jí)別操作,即每次執(zhí)行flush都需要整個(gè)region中的所有store全都執(zhí)行flush。接下來作為延伸閱讀內(nèi)容,對(duì)Per-CF Flush比較感興趣的可以繼續(xù)閱讀,Per-CF Flush允許系統(tǒng)對(duì)某個(gè)或某些列組單獨(dú)執(zhí)行flush。實(shí)現(xiàn)原理與上文所分析內(nèi)容基本相似。不同的是上文中 oldestUnflushedSequenceId是與region一一對(duì)應(yīng)的,Per-CF Flush中這個(gè)參數(shù)需要細(xì)化到store,與store一一對(duì)應(yīng)。

延伸閱讀:Per-CF Flush

region級(jí)別flush確實(shí)存在不少問題,在多個(gè)列族的情況下其中一個(gè)store大小超過了閾值(128M),不論其他store多大多小都會(huì)強(qiáng)制落盤,有些很小的列族(幾兆)落盤后形成很多特別小的文件,對(duì)hbase的讀并不是一件好事。

per-cf flush允許單個(gè)store執(zhí)行flush,該feature在1.0.0以上版本已經(jīng)存在,在1.2.0版本設(shè)置為默認(rèn)策略。 實(shí)現(xiàn)這個(gè)功能有兩個(gè)必要的工作,其一是提出一種新的flush策略能夠在多個(gè)列族中選擇一個(gè)或者多個(gè)單獨(dú)進(jìn)行進(jìn)行flush,目前新策略稱為FlushLargerStoresPolicy,即選擇當(dāng)前最大的一個(gè)store進(jìn)行flush。其二是必須將oldestUnflushedSequenceId的粒度從region細(xì)化到store,即從map改為map>,上文所述三個(gè)問題的判斷邏輯也需要修改為store級(jí)別判斷邏輯。這里使用store級(jí)別判斷邏輯簡單對(duì)問題一和問題三進(jìn)行復(fù)盤。

Per-CF Flush策略下,HLog在什么時(shí)候可以過期回收?

region級(jí)別的判斷邏輯主要依賴于map,詳見上文。store級(jí)別的數(shù)據(jù)結(jié)構(gòu)改為了map>,其實(shí)很容易經(jīng)過簡單的轉(zhuǎn)化又變回region級(jí)別,map找到最小的oldestUnflushedSequenceId稱為minSeqNum,這樣region級(jí)別的數(shù)據(jù)結(jié)構(gòu)就變出來了 – map,其他邏輯都不用變。

Per-CF Flush策略下,RegionServer宕機(jī)恢復(fù)replay日志時(shí)哪些數(shù)據(jù)需要被回放,哪些會(huì)被skip?

這個(gè)問題稍微復(fù)雜一點(diǎn),第一個(gè)關(guān)注的問題是回放粒度的問題。需要回過頭來看看HLog中Entry的組成,如圖可以知道一個(gè)Entry由WALKey和WAKEdit兩部分構(gòu)成,WALKey包含一些基本信息,本文重點(diǎn)關(guān)注sequenceId這個(gè)變量; WALEdit包含插入\更新的KeyValue集合,這里需要重點(diǎn)注意, 這些KeyValue可能包含一行中多個(gè)列族(列),因此可以說WALEdit會(huì)包含多個(gè)store更新的KeyValue 。
HBase原理——要弄懂的sequenceId

在All-CF Flush策略下,我們以HLog-Entry為粒度進(jìn)行數(shù)據(jù)回放沒有任何問題,但是在Per-CF Flush策略下就不再行得通。因?yàn)橐粋€(gè)HLog-Entry中多個(gè)CF的KeyValue是混在一起的,可能部分KV已經(jīng)落盤,其他部分還沒有。因此需要將回放粒度減小到KeyValue級(jí)別,一個(gè)一個(gè)KeyValue分別進(jìn)行檢查回放。

回放粒度問題摸清了,再來關(guān)注哪些KeyValue需要被回放,哪些會(huì)被skip。上文說過,每次flush的時(shí)候?qū)?yīng)的oldestUnflushedSequenceId會(huì)被持久化到HFile的元數(shù)據(jù)中。在All-CF Flush策略下,一次flush操作中整個(gè)region所有store所持久化的oldestUnflushedSequenceId都相同,因此回放的時(shí)候HLog-Entry的sequenceId只需要與這一個(gè)oldestUnflushedSequenceId比較就可以,大的話就需要回放,小的話就skip。但在Per-CF的場景下又不再行得通,一個(gè)region中不同store都有自己獨(dú)立的oldestUnflushedSequenceId,因此回放的時(shí)候需要根據(jù)KeyValue找到對(duì)應(yīng)store,在與該store中的oldestUnflushedSequenceId比較,大的話需要回放,小的話skip。

總結(jié)起來就是:skip hlog cells per store when replaying,注意這里蘊(yùn)含兩個(gè)點(diǎn): hlog cells 以及 per store。

全文總結(jié)

本文從hbase中非常重要的一個(gè)變量(sequenceId)入手,將其所涉及到的WAL模塊、Flush模塊分別進(jìn)行了說明。文中只講了一個(gè)大概,很多細(xì)節(jié)知識(shí)并沒有深究,有興趣的同學(xué)可以根據(jù)文中所講內(nèi)容深入源碼,相信會(huì)比較容易。接下來筆者將會(huì)繼續(xù)根據(jù)sequenceId這個(gè)話題分析HBase中MVCC機(jī)制,敬請(qǐng)期待!

為了幫助大家讓學(xué)習(xí)變得輕松、高效,給大家免費(fèi)分享一大批資料,幫助大家在成為大數(shù)據(jù)工程師,乃至架構(gòu)師的路上披荊斬棘。在這里給大家推薦一個(gè)大數(shù)據(jù)學(xué)習(xí)交流圈:658558542 歡迎大家進(jìn)×××流討論,學(xué)習(xí)交流,共同進(jìn)步。

當(dāng)真正開始學(xué)習(xí)的時(shí)候難免不知道從哪入手,導(dǎo)致效率低下影響繼續(xù)學(xué)習(xí)的信心。

但最重要的是不知道哪些技術(shù)需要重點(diǎn)掌握,學(xué)習(xí)時(shí)頻繁踩坑,最終浪費(fèi)大量時(shí)間,所以有有效資源還是很有必要的。

最后祝福所有遇到瓶疾且不知道怎么辦的大數(shù)據(jù)程序員們,祝福大家在往后的工作與面試中一切順利

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI