Hbase split的三種方式和split的過程

在Hbase中split是一個很重要的功能,Hbase是經過把數據分配到必定數量的region來達到負載均衡的。一個table會被分配到一個或多個region中,這些region會被分配到一個或者多個regionServer中。在自動split策略中,當一個region達到必定的大小就會自動split成兩個region。table在region中是按照row key來排序的,而且一個row key所對應的行只會存儲在一個region中,這一點保證了Hbase的強一致性 。html

        

在一個region中有一個或多個stroe,每一個stroe對應一個column families(列族)。一個store中包含一個memstore 和 0 或 多個store files。每一個column family 是分開存放和分開訪問的。java

 

Pre-splittingnode

當一個table剛被建立的時候,Hbase默認的分配一個region給table。也就是說這個時候,全部的讀寫請求都會訪問到同一個regionServer的同一個region中,這個時候就達不到負載均衡的效果了,集羣中的其餘regionServer就可能會處於比較空閒的狀態。解決這個問題能夠用pre-splitting,在建立table的時候就配置好,生成多個region。算法

 

在table初始化的時候若是不配置的話,Hbase是不知道如何去split region的,由於Hbase不知道應該那個row key能夠做爲split的開始點。若是咱們能夠大概預測到row key的分佈,咱們可使用pre-spliting來幫助咱們提早split region。不過若是咱們預測得不許確的話,仍是可能致使某個region過熱,被集中訪問,不過還好咱們還有auto-split。最好的辦法就是首先預測split的切分點,作pre-splitting,而後後面讓auto-split來處理後面的負載均衡。shell

 

Hbase自帶了兩種pre-split的算法,分別是 HexStringSplit 和  UniformSplit 。若是咱們的row key是十六進制的字符串做爲前綴的,就比較適合用HexStringSplit,做爲pre-split的算法。例如,咱們使用HexHash(prefix)做爲row key的前綴,其中Hexhash爲最終獲得十六進制字符串的hash算法。咱們也能夠用咱們本身的split算法。apache

在hbase shell 下:緩存

hbase org.apache.hadoop.hbase.util.RegionSplitter pre_split_table HexStringSplit -c 10 -f f1

 

-c 10 的意思爲,最終的region數目爲10個;-f  f1爲建立一個那麼爲f1的 column family.數據結構


執行scan 'hbase:meta' 能夠看到meta表中的,負載均衡

      

 

只截取了meta表中的2個region的記錄(一共10個region),分別是rowkey範圍是 '' ''~19999999 和19999999~33333332的region。oop

咱們也能夠自定義切分點,例如在hbase shell下使用以下命令:

create 't1', 'f1', {SPLITS => ['10', '20', '30', '40']}

 

自動splitting

 

當一個reion達到必定的大小,他會自動split稱兩個region。若是咱們的Hbase版本是0.94 ,那麼默認的有三種自動split的策略,ConstantSizeRegionSplitPolicy,IncreasingToUpperBoundRegionSplitPolicy還有 KeyPrefixRegionSplitPolicy.

 

在0.94版本以前ConstantSizeRegionSplitPolicy 是默認和惟一的split策略。當某個store(對應一個column family)的大小大於配置值 ‘hbase.hregion.max.filesize’的時候(默認10G)region就會自動分裂。

 

而0.94版本中,IncreasingToUpperBoundRegionSplitPolicy 是默認的split策略。

這個策略中,最小的分裂大小和table的某個region server的region 個數有關,當store file的大小大於以下公式得出的值的時候就會split,公式以下

 

Min (R^2 * 「hbase.hregion.memstore.flush.size」, 「hbase.hregion.max.filesize」)  R爲同一個table中在同一個region server中region的個數。

 

例如:

hbase.hregion.memstore.flush.size 默認值 128MB。

hbase.hregion.max.filesize默認值爲10GB 。

  • 若是初始時R=1,那麼Min(128MB,10GB)=128MB,也就是說在第一個flush的時候就會觸發分裂操做。
  • 當R=2的時候Min(2*2*128MB,10GB)=512MB ,當某個store file大小達到512MB的時候,就會觸發分裂。
  •  如此類推,當R=9的時候,store file 達到10GB的時候就會分裂,也就是說當R>=9的時候,store file 達到10GB的時候就會分裂。

 

split 點都位於region中row key的中間點。

 

KeyPrefixRegionSplitPolicy能夠保證相同的前綴的row保存在同一個region中。

指定rowkey前綴位數劃分region,經過讀取 KeyPrefixRegionSplitPolicy.prefix_length  屬性,該屬性爲數字類型,表示前綴長度,在進行split時,按此長度對splitPoint進行截取。此種策略比較適合固定前綴的rowkey。當table中沒有設置該屬性,指定此策略效果等同與使用IncreasingToUpperBoundRegionSplitPolicy。

 

咱們能夠經過配置 hbase.regionserver.region.split.policy 來指定split策略,咱們也能夠寫咱們本身的split策略。

 

強制split

 

Hbase 容許客戶端強制執行split,在hbase shell中執行如下命令:

 split 'forced_table', 'b' //其中forced_table 爲要split的table , ‘b’ 爲split 點

 

region splits 執行過程:

 

region server處理寫請求的時候,會先寫入memstore,當memstore 達到必定大小的時候,會寫入磁盤成爲一個store file。這個過程叫作 memstore flush。當store files 堆積到必定大小的時候,region server 會 執行‘compact’操做,把他們合成一個大的文件。 當每次執行完flush 或者compact操做,都會判斷是否須要split。當發生split的時候,會生成兩個region A 和 region B可是parent region數據file並不會發生複製等操做,而是region A 和region B 會有這些file的引用。這些引用文件會在下次發生compact操做的時候清理掉,而且當region中有引用文件的時候是不會再進行split操做的。這個地方須要注意一下,若是當region中存在引用文件的時候,並且寫操做很頻繁和集中,可能會出現region變得很大,可是卻不split。由於寫操做比較頻繁和集中,可是沒有均勻到每一個引用文件上去,因此region一直存在引用文件,不能進行分裂,這篇文章講到了這個狀況,總結得挺好的。http://koven2049.iteye.com/blog/1199519 

 

雖然split region操做是region server單獨肯定的,可是split過程必須和不少其餘部件合做。region server 在split開始前和結束前通知master,而且須要更新.META.表,這樣,客戶端就能知道有新的region。在hdfs中從新排列目錄結構和數據文件。split是一個複雜的操做。在split region的時候會記錄當前執行的狀態,當出錯的時候,會根據狀態進行回滾。下圖表示split中,執行的過程。(紅色線表示region server 或者master的操做,綠色線表示client的操做。)

 

1.region server 決定split region,第一步,region server在zookeeper中建立在

/hbase/region-in-transition/region-name 目錄下,建立一個znode,狀態爲SPLITTING.

 

2.由於master有對 region-in-transition 的znode作監聽,因此,mater的得知parent region須要split

 

3.region server  在hdfs的parent region的目錄下建立一個名爲「.splits」的子目錄

 

4.region server 關閉parent region。強制flush緩存,而且在本地數據結構中標記region爲下線狀態。若是這個時候客戶端恰好請求到parent region,會拋出NotServingRegionException。這時客戶端會進行補償性重試。

 

5.region server在.split 目錄下分別爲兩個daughter region建立目錄和必要的數據結構。而後建立兩個引用文件指向parent regions的文件。

 

6.region server 在HDFS中,建立真正的region目錄,而且把引用文件移到對應的目錄下。

 

7.region server 發送一個put的請求到.META.表中,而且在.META.表中設置parent region爲下線狀態,而且在parent region對應的row中兩個daughter region的信息。可是這個時候在.META.表中daughter region 還不是獨立的row。這個時候若是client scan .META.表,會發現parent region正在split,可是client還看不到daughter region的信息。當這個put 成功以後,parent region split會被正在的執行。若是在 RPC 成功以前 region server 就失敗了,master和下次打開parent region的region server 會清除關於此次split的髒狀態。可是當RPC返回結果給到parent region ,即.META.成功更新以後,,region split的流程還會繼續進行下去。至關因而個補償機制,下次在打開這個parent region的時候會進行相應的清理操做。

 

8.region server 打開兩個daughter region接受寫操做。

 

9.region server 在.META.表中增長daughters A 和 B  region的相關信息,在這之後,client就能發現這兩個新的regions而且能發送請求到這兩個新的region了。client本地具體有.META.表的緩存,當他們訪問到parent region的時候,發現parent region下線了,就會從新訪問.META.表獲取最新的信息,而且更新本地緩存。

 

10.region server 更新 znode  的狀態爲SPLIT。master就能知道狀態更新了,master的平衡機制會判斷是否須要把daughter regions 分配到其餘region server 中。

 

11.在split以後,meta和HDFS依然會有引用指向parent region. 當compact 操做發生在daughter regions中,會重寫數據file,這個時候引用就會被逐漸的去掉。垃圾回收任務會定時檢測daughter regions是否還有引用指向parent files,若是沒有引用指向parent files的話,parent region 就會被刪除。

 

參考鏈接:

http://hortonworks.com/blog/apache-hbase-region-splitting-and-merging/ Hbase split

http://hbase.apache.org/book/regions.arch.html Hbase 官方文檔(region)

http://blog.javachen.com/2014/01/16/hbase-region-split-policy/ split策略

http://blackproof.iteye.com/blog/2037159 split源碼解析

ZOOM 雲視頻會議網站:http://www.zoomonline.cn/

相關文章
相關標籤/搜索