作用
– HBase自動(dòng)把表水平劃分成多個(gè)區(qū)域(region),每個(gè)region會(huì)保存一個(gè)表 里面某段連續(xù)的數(shù)據(jù);每個(gè)表一開始只有一個(gè)region,隨著數(shù)據(jù)不斷插 入表,
- region不斷增大,當(dāng)增大到一個(gè)閥值的時(shí)候,region就會(huì)等分會(huì) 兩個(gè)新的region(裂變);
– 當(dāng)table中的行不斷增多,就會(huì)有越來越多的region。這樣一張完整的表 被保存在多個(gè)Regionserver上。
層級(jí)結(jié)構(gòu)
Table (HBase 表)
Region(表的Regions)
Store(Region中以列族為單位的單元)
MemStore (用于寫緩存)
StoreFile (StoreFiles for each Store for each Region for the table) 存儲(chǔ)在磁盤上的文件(HFile)
- Block (讀寫的最小單元)
Region分裂
1、根據(jù)rowkey來分裂定位切分點(diǎn)
那切分點(diǎn)是如何定位的呢? 整個(gè)region中最大store中的最大文件中最中心的一個(gè)block的首個(gè)rowkey 。這是一句比較消耗腦力的語句,需要細(xì)細(xì)品味。另外,HBase還規(guī)定,如果定位到的rowkey是整個(gè)文件的首個(gè)rowkey或者最后一個(gè)rowkey的話,就認(rèn)為沒有切分點(diǎn)。
什么情況下會(huì)出現(xiàn)沒有切分點(diǎn)的場(chǎng)景呢?最常見的就是一個(gè)文件只有一個(gè)block,執(zhí)行split的時(shí)候就會(huì)發(fā)現(xiàn)無法切分。很多新同學(xué)在測(cè)試split的時(shí)候往往都是新建一張新表,然后往新表中插入幾條數(shù)據(jù)并執(zhí)行一下flush,再執(zhí)行split,奇跡般地發(fā)現(xiàn)數(shù)據(jù)表并沒有真正執(zhí)行切分。原因就在這里,這個(gè)時(shí)候仔細(xì)的話你翻看debug日志是可以看到這樣的日志滴:

2、事務(wù)性執(zhí)行分裂
HBase將整個(gè)切分過程包裝成了一個(gè)事務(wù),意圖能夠保證切分事務(wù)的原子性。整個(gè)分裂事務(wù)過程分為三個(gè)階段:prepare – execute – (rollback) ,操作模版如下:

prepare階段:
在內(nèi)存中初始化兩個(gè)子region,具體是生成兩個(gè)HRegionInfo對(duì)象,包含tableName、regionName、startkey、endkey等。同時(shí)會(huì)生成一個(gè)transaction journal,這個(gè)對(duì)象用來記錄切分的進(jìn)展,具體見rollback階段。
執(zhí)行階段
regionserver 更改ZK節(jié)點(diǎn) /region-in-transition 中該region的狀態(tài)為SPLITING。
master通過watch節(jié)點(diǎn)/region-in-transition檢測(cè)到region狀態(tài)改變,并修改內(nèi)存中region的狀態(tài),在master頁面RIT模塊就可以看到region執(zhí)行split的狀態(tài)信息。
在父存儲(chǔ)目錄下新建臨時(shí)文件夾.split保存split后的daughter region信息。
關(guān)閉parent region:parent region關(guān)閉數(shù)據(jù)寫入并觸發(fā)flush操作,將寫入region的數(shù)據(jù)全部持久化到磁盤。此后短時(shí)間內(nèi)客戶端落在父region上的請(qǐng)求都會(huì)拋出異常NotServingRegionException。
核心分裂步驟:在.split文件夾下新建兩個(gè)子文件夾,稱之為daughter A、daughter B,并在文件夾中生成reference文件,分別指向父region中對(duì)應(yīng)文件。這個(gè)步驟是所有步驟中最核心的一個(gè)環(huán)節(jié),生成reference文件日志如下所示:
2017-08-12 11:53:38,158 DEBUG [StoreOpener-0155388346c3c919d3f05d7188e885e0-1] regionserver.StoreFileInfo: reference 'hdfs://hdfscluster/hbase-rsgroup/data/default/music/0155388346c3c919d3f05d7188e885e0/cf/d24415c4fb44427b8f698143e5c4d9dc.00bb6239169411e4d0ecb6ddfdbacf66' to region=00bb6239169411e4d0ecb6ddfdbacf66 hfile=d24415c4fb44427b8f698143e5c4d9dc。
reference文件是一個(gè)引用文件(并非linux鏈接文件),文件內(nèi)容很顯然不是用戶數(shù)據(jù)。
文件內(nèi)容其實(shí)非常簡(jiǎn)單,主要有兩部分構(gòu)成:
其一是切分點(diǎn) splitkey
其二是一個(gè)boolean類型的變量(true或者false),true表示該reference文件引用的是父文件的上半部分(top),而false表示引用的是下半部分 (bottom)。

父region分裂為兩個(gè)子region后, 將daughter A、daughter B拷貝到HBase根目錄下,形成兩個(gè)新的region
parent region通知修改 hbase.meta 表后下線,不再提供服務(wù)。下線后parent region在meta表中的信息并不會(huì)馬上刪除,而是標(biāo)注split列、offline列為true,并記錄兩個(gè)子region。
開啟daughter A、daughter B兩個(gè)子region。通知修改 hbase.meta 表,正式對(duì)外提供服務(wù)。
rollback階段:
如果execute階段出現(xiàn)異常,則執(zhí)行rollback操作。為了實(shí)現(xiàn)回滾,整個(gè)切分過程被分為很多子階段,回滾程序會(huì)根據(jù)當(dāng)前進(jìn)展到哪個(gè)子階段清理對(duì)應(yīng)的垃圾數(shù)據(jù)。代碼中使用 JournalEntryType 來表征各個(gè)子階段,
分裂問題
1、通過reference文件如何查找數(shù)據(jù)?
(1)根據(jù)reference文件名(region名+真實(shí)文件名)定位到真實(shí)數(shù)據(jù)所在文件路徑
(2)定位到真實(shí)數(shù)據(jù)文件就可以在整個(gè)文件中掃描待查KV了么?非也。因?yàn)閞eference文件通常都只引用了數(shù)據(jù)文件的一半數(shù)據(jù),以切分點(diǎn)為界,要么上半部分文件數(shù)據(jù),要么下半部分?jǐn)?shù)據(jù)。那到底哪部分?jǐn)?shù)據(jù)?切分點(diǎn)又是哪個(gè)點(diǎn)?還記得上文又提到reference文件的文件內(nèi)容吧,沒錯(cuò),就記錄在文件中。
文件內(nèi)容其實(shí)非常簡(jiǎn)單,主要有兩部分構(gòu)成:其一是切分點(diǎn) splitkey,其二是一個(gè)boolean類型的變量(true或者false),true表示該reference文件引用的是父文件的上半部分(top),而false表示引用的是下半部分 (bottom)。
2、父region的數(shù)據(jù)什么時(shí)候會(huì)遷移到子region目錄?
答案是子region發(fā)生major_compaction時(shí)。我們知道compaction的執(zhí)行實(shí)際上是將store中所有小文件一個(gè)KV一個(gè)KV從小到大讀出來之后再順序?qū)懭胍粋€(gè)大文件,完成之后再將小文件刪掉,因此compaction本身就需要讀取并寫入大量數(shù)據(jù)。子region執(zhí)行major_compaction后會(huì)將父目錄中屬于該子region的所有數(shù)據(jù)讀出來并寫入子region目錄數(shù)據(jù)文件中??梢妼?shù)據(jù)遷移放到compaction這個(gè)階段來做,是一件順便的事。
3、父region什么時(shí)候會(huì)被刪除?
實(shí)際上HMaster會(huì)啟動(dòng)一個(gè)線程定期遍歷檢查所有處于splitting狀態(tài)的父region,確定檢查父region是否可以被清理。檢測(cè)線程首先會(huì)在meta表中揪出所有split列為true的region,并加載出其分裂后生成的兩個(gè)子region(meta表中splitA列和splitB列), 只需要檢查此兩個(gè)子region是否還存在引用文件,如果都不存在引用文件就可以認(rèn)為該父region對(duì)應(yīng)的文件可以被刪除?,F(xiàn)在再來看看上文中父目錄在meta表中的信息,就大概可以理解為什么會(huì)存儲(chǔ)這些信息了:

生產(chǎn)環(huán)境
【禁用自動(dòng)切分region,改用手動(dòng)切分】
上面說的都是自動(dòng)切分來實(shí)現(xiàn)的負(fù)載均衡。建議在生產(chǎn)環(huán)境中禁用自動(dòng)的split(或者將Region設(shè)置的大一點(diǎn)),然后手動(dòng)切割region,可以在晚上或者業(yè)務(wù)不忙(例如沒有大量寫操作)的時(shí)候手動(dòng)執(zhí)行split。
執(zhí)行split操作后,Hbase內(nèi)部的邏輯是:
第一輪split,遍歷所有region的信息,如果region size大于某值(比如4G)則split該region;
如果一輪后沒有大于該值的region則結(jié)束,如果還有大于該值的region則繼續(xù)新一輪split,直到?jīng)]有region大于該閾值為止。
如何判斷split已完成:檢查hdfs上老的region目錄是否已被清除來判斷split是否已完成。
Region 合并
意義
- 當(dāng)存在大量沒有數(shù)據(jù)的region時(shí),執(zhí)行region的合并來避免region過多
- 之所以會(huì)存在大量沒有數(shù)據(jù)的region是因?yàn)闉榱吮苊鈘egion到達(dá)閥值引起分裂的開銷,創(chuàng)建表格時(shí)先進(jìn)行預(yù)分區(qū)。
步驟
- 客戶端發(fā)送指令給Master
- Master收到指令后將要合并的region移動(dòng)到指定的RegionServer
- Master發(fā)送Merge請(qǐng)求給指定的RegionServer執(zhí)行合并操作
- 最后將被合并的regions從hbase:meta中刪除并添加合并后的region