1. 程式人生 > >HBase Region 的分裂

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節點