HBase Region 的分裂


轉:http://www.tuicool.com/articles/jQvEVvu


分裂策略

不同的分裂策略的實現需要繼承RegionSplitPolicy,主要實現兩個方法:

  1. shouldSplit()表示是否需要分裂
  2. getSplitPoint()得到分裂點rowkey

從 HBase 0.94之後,默認的分裂策略是IncreasingToUpperBoundRegionSplitPolicy ,思想就是當Region的大小超過某個閾值時,即進行分裂。

這個閾值主要由如下幾個因素決定:

  1. hbase.hregion.max.filesize
  2. hbase.increasing.policy.initial.size
  3. 當前Region所在RegionServer上和當前Region屬於同一張表的Region個數

根據以上三個因素算出一個閾值後,如果當前Region有某個Store的大小大於這個閾值,則認爲該Region可分裂,這裏對於Store還有一個條件就是Store下不能存在reference類型的StoreFile,這種reference類型的StoreFile是一次分裂後產生的,後續會詳說。

對於IncreasingToUpperBoundRegionSplitPolicy來說,使用基類中默認的getSplitPoint()函數,即將Region中size最大的Store下最大的StoreFile拿出來,然後根據block index找出StoreFile中間的block,那麼這個block的startkey就是split point

分裂實現

在後臺flush線程flush完成一個region內部的memstore時,會去檢查這個region是否需要分裂,如果需要分裂,會提交一個SplitRequest任務給後臺的compactSplitThread線程內部的負責split的線程池,SplitRequest內部會創建一個SplitTransaction來完成split

  • 根據待分裂region和split point生成兩個HRegionInfo對象,代表分裂後產生的兩個dautghter region
  • 在zk上創建一個ephemeral node,路徑是 /hbase/region-in-transition/regionEncodedName,節點內容爲了通知master某個region server想split 
    某個region,兩個子region的信息,包括range等,需要通知master原因是防止master對這個 
    region進行遷移等等
  • 等待master批准region server split
  • 在hdfs上爲這個region的split過程創建臨時工作目錄/hbase/data/namespace/tableName/regionEncodedName/.splits
  • 關閉當前待分裂region

    • 將region的writestate的writesEnabled置爲false,告訴後臺的compact和flush線程不要再工作了
    • 如果當前region內的memstore size大於hbase.hregion.preclose.flush.size,默認5MB,那麼先做一次pre flush。這裏最開始時已經進行了flush region的操作,在flush region完成到現在中間可能還有寫操作寫入當前region內的各個store的memstore中,由於關閉region期間region不能提供讀寫服務,並且關閉region期間需要將region中的memstore進行flush,所以爲了讓region的不能提供讀寫服務時間變少,這裏做一個pre flush,後續再真正關閉region
    • 置上region的closing標記,導致region停讀寫。
    • flush當前region的所有memstore,並且將region的所有storefile關閉
    • 置上region的closed標記
    • 將region從region server的online region列表中刪除
  • 開始split 當前region的store file(splitStoreFiles),爲region下的每個storefile都創建一個StoreFileSplitter任務,交給線程池處理。StoreFileSplitter任務實際上沒有真正的劈開

    storefile,生成兩個小的storefile,而是生成兩個類型爲reference的storefile文件,文件名和內容都比較特殊,比如:假設region encoded name爲aaaa的region,分裂爲兩個name爲bbbb和cccc的region,aaaa下有一個column family叫做cfA,下面有一個名

    爲hfileA的storefile,那麼三個region的目錄結構如下

    /hbase/data/namespace/tableName/aaaa/cfA/hfileA
    /hbase/data/namespace/tableName/bbbb/.splits/cfA/hfileA.aaaa
    /hbase/data/namespace/tableName/cccc/.splits/cfA/hfileA.aaaa
    從最後的hfile文件名可以看到,子region引用了父親region的同名的hfile,這兩個特殊的文件裏沒有真實的數據,而是一個索引數據,記着split row是什麼,並且自己是split row的前半部分還是後半部分(Reference).
  • 往兩個子region的目錄中寫入.regioninfo文件,並且將臨時目錄改名,目錄結構如下

    /hbase/data/namespace/tableName/bbbb/cfA/hfileA.aaaa
    /hbase/data/namespace/tableName/cccc/cfA/hfileA.aaaa
  • 原子的修改meta table,在meta table裏面標記父親region下線,並且split爲兩個region, 
    並且在meta table中加入兩個子region對應的項 
    - 打開兩個子region,更新meta table,將location記錄其中
  • 將兩個子region加入region server的online region列表中
  • 請求一個compaction操作,後臺的compaction操作最終會清理掉這些reference文件
  • 更新zk上節點的狀態,告訴master已經split完成
  • 等待master刪除zk節點


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章