HBase是以Region為最小的存儲和負載單元(這里可不是HDFS的存儲單元),因此Region的負載管理,關系到了數據讀寫的性能。先拋開Region如何切分不說,看看Region是如何分配到各個RegionServer的吧。
更多內容參考——我的大數據學習之路
Region在HBase中的角色

Table (HBase表)
Region (Region)
Store (每個Region的每個列族獨立存儲)
MemStore (MemStore每個Store有一個,用於在內存中保存數據)
StoreFile (StoreFiles對應於Store,是具體存儲在磁盤的文件)
Block (Blocks是HDFS上的存儲單元)
Region的管理
一般來說對於每個Region Server,官方推薦最好是控制Region的數量在20-200個、大小在5-20Gb左右。
為什么要控制region的數量呢?
- 默認MemStore需要2MB的空間用來存儲數據,如果一台機器上有1000個Region,每個有兩個列族,那就需要3.9GB的數據。
- 如果同時以某個相同的頻率更新所有的Region,當同時進行數據持久化的時候也會有問題
- Master對於維護大量的Region有很大的性能問題,因為在平衡Region的時候,在ZK中的操作都是同步的。
- Region Server需要維護Region的索引信息
那么Region Server是如何管理Region的呢?
啟動
- Master創建AssignmentManager
- AssignmentManager查看當前的Region分配信息
- 滿足條件后,通過LoadBalancerFactory創建LoadBalancer,1.0后的版本默認是StochasticLoadBalancer
- 判斷是否需要進行負載平衡,並更新相關信息
容錯
- 如果平衡負載的時候報錯,RegionServer會直接關閉
- Master檢測到resgion Server異常
- 重啟Region server
- 請求進行重試;超時會請求其他的節點
Region的狀態機
Hbase中每個Region自己維護其在hbase:meta表中的信息。

狀態機中包括下面幾種狀態:
- offline:region離線沒有開啟
- opening:region正在被打開
- open:region正在打開,並且region server通知了master
- failed_open:regionserver打開失敗
- closing:region正在被關閉
- closed:regionserver正在關閉,並且已經通知了master
- failed_close:regionserver關閉失敗了
- splitting:region server通知master,region正在被切分
- split:region server通知master,region已經被切分完了
- spliting_new:region是切分過程中新建的文件
- merging:regionserver通知master region正在合並
- merged:regionserver通知master region合並完了
- merging_new:region是合並新建出來的
不同的顏色是不同含義:
- 棕色:離線狀態,屬於一種短暫的瞬間狀態(比如關閉后開啟的中間狀態)、停止狀態或者初始化的時候的狀態
- 綠色:正常的狀態,可以支持請求訪問
- 藍色:短暫的狀態
- 紅色:失敗
- 黃色:合並或者切分的狀態
- 灰色:剛開始的狀態
各個序號代表不同的操作場景:
- Master向region server發起region從offline到openning的狀態請求,regionserver如果沒有收到,master會嘗試重試幾次。RegionServer接收到請求后,regin狀態變成opening
- 如果Master發起的open請求超過次數,那么無論region server是否已經打開region,master都會命令region server關閉文件,狀態變為closing
- 當region server打開region后,會嘗試通知master,讓他把region狀態修改為open,並通知regsion server。這樣region才能變為open狀態
- 如果region server打開四百,會嘗試通知master。master會把region的狀態變更為closed,並且嘗試去其他的region server打開region
- 如果master嘗試幾次后,都沒有打開region,就會把狀態變更為failed_open
- master通知region server關閉region,如果沒有反應,會重試
- 如果region server沒有在線,會拋出異常。然后region的狀態會變成closing
- 如果region server在線,但是好幾次都沒響應,就會更新狀態為failed_close
- 如果region server收到請求,並且關閉了region,那么會通知master把region狀態修改為closed。並且把region分配給其他的server
- 在分配之前,master會先把region從closed狀態轉換為offline
- 如果region server正在切分region,會通知mastere。master把region狀態由open變為splitting,並且把新增兩個region的信息,這兩個region都是splitting_new狀態
- 如果region切分成功,當前的region狀態從splitting變成split;新增的兩個region狀態從splitting_new變成open
- 如果切分失敗,狀態從splitting回到open,兩個region也從splitting_new變成offline
- 如果region server想要合並兩個region,那么也會先通知master。master把兩個region從open變成merging,然后增加一個新的region,狀態為merging_new
- 如果合並成功, 舊的region從merging變為merged,新的region從merging_new變為open
- 如果合並失敗,region的狀態從merging變回open,新建的一個region狀態又變成offline
- 如果管理員通過hbase shell操作分配region,master會嘗試把失敗的狀態變成close
Region的數據本地性
數據本地性通過來自於hdfs client和hdfs block存儲的節點差異性,針對數據備份來說,會按照下面的機制進行:
- 第一個備份會優先卸載本地node節點上
- 第二個備份會隨機選擇一個不同的機架
- 第三個備份會在第二個備份所在的機架上,再隨機選擇一個節點
- 如果還有其他的備份節點,就在集群中隨機選擇了。
這樣Hbase在刷新或者壓縮時,可以體現數據的本地性。如果一個region server出現故障,那么就沒有數據本地性可言了,因為它的備份都在其他的節點上。
Region的切分
HBase會配置一個切分的閾值,當到達閾值后,就會執行region的切分。Master不會參與Region的切分,切分由Region Server獨立完成。執行切分的時候,會先把region下線,然后在meta表中增加子region的信息,最后通知給master。
默認使用的切分策略是IncreasingToUpperBoundRegionSplitPolicy(1.2.0版本),通過修改配置可以切換切分規則:
<property>
<name>hbase.regionserver.region.split.policy</name>
<value>org.apache.hadoop.hbase.regionserver.IncreasingToUpperBoundRegionSplitPolicy</value>
</property>
也可以通過Admin API指定規則:
HTableDescriptor tableDesc = new HTableDescriptor("test");
tableDesc.setValue(HTableDescriptor.SPLIT_POLICY, ConstantSizeRegionSplitPolicy.class.getName());
tableDesc.addFamily(new HColumnDescriptor(Bytes.toBytes("cf1")));
admin.createTable(tableDesc);
或者通過HBase shell管理:
hbase> create 'test', {METHOD => 'table_att', CONFIG => {'SPLIT_POLICY' => 'org.apache.hadoop.hbase.regionserver.ConstantSizeRegionSplitPolicy'}},
{NAME => 'cf1'}
也可以通過HBaseConfiguration來配置:
HTableDescriptor myHtd = ...;
myHtd.setValue(HTableDescriptor.SPLIT_POLICY, MyCustomSplitPolicy.class.getName());
Region的手動切分
Region的切分可以在表創建的時候來執行,也可已在后期來做。最好是在設計表結構的時候,就把切分的規則考慮進去。因為:
- 如果你的數據rowkey是隨着時間自增長的,那么所有的新數據都會寫在最后一個Region中,這樣會導致總是最后一個region是熱點,而其他的所有region基本都閑置了。
- 有的時候是一些意外的情況導致的熱點問題,比如table中存儲的是每個網頁對應的點擊日志,如果一個網頁很受歡迎,那么它對應的region將會成為熱點。
- 當集群的region很多的時候,想要加快加載數據的速度
- 在批量導入的時候,可能會造成region熱點寫
設計切分點
默認HBase都是基於Rowkey的字符進行切分的。如果rowkey是通過數字開頭,那么會按照數字的范圍進行切分;如果是字母,則會通過它的ASCII碼進行切分。用戶也可以自定義切分的算法,比如HexStringSplit通過轉換成十六進制進行切分。
Region的合並
Master和RegionServer都會參與Region的合並。一般是Client發送合並的請求到Master,然后Master把需要合並的region移動到需要移動比例最高的那個Regsion Server上。比如現在有ABC3個Region Server,A有2個Region,B和C都只有一個,那么會把Region都轉移到A Server,再執行合並操作。跟切分的過程一樣,也需要先將region設置離線,然后執行合並,再去更新meta表信息。
下面是Hbase shell中合並的例子:
$ hbase> merge_region 'ENCODED_REGIONNAME', 'ENCODED_REGIONNAME'
$ hbase> merge_region 'ENCODED_REGIONNAME', 'ENCODED_REGIONNAME', true
合並操作是異步操作,發送請求后,客戶端這邊不需要登到合並結束。
第三個參數,表示是否強制合並。因為默認合並操作只能針對相鄰的region,force參數可以強制跨Region的合並。
