做者:範欣欣(本篇文章僅限內部分享,如需轉載,請聯繫網易獲取受權。)
Region自動切分是HBase可以擁有良好擴張性的最重要因素之一,也必然是全部分佈式系統追求無限擴展性的一副良藥。HBase系統中Region自動切分是如何實現的?這裏面涉及不少知識點,好比Region切分的觸發條件是什麼?Region切分的切分點在哪裏? 如何切分才能最大的保證Region的可用性?如何作好切分過程當中的異常處理?切分過程當中要不要將數據移動?等等,這篇文章將會對這些細節進行基本的說明,一方面可讓你們對HBase中Region自動切分有更加深刻的理解,另外一方面若是想實現相似的功能也能夠參考HBase的實現方案。 Region切分觸發策略 在最新穩定版(1.2.6)中,HBase已經有多達6種切分觸發策略。固然,每種觸發策略都有各自的適用場景,用戶能夠根據業務在表級別選擇不一樣的切分觸發策略。常見的切分策略以下圖:
-
IncreasingToUpperBoundRegionSplitPolicy: 0.94版本~2.0版本默認切分策略。這種切分策略微微有些複雜,整體來看和ConstantSizeRegionSplitPolicy思路相同,一個region中最大store大小大於設置閾值就會觸發切分。可是這個閾值並不像ConstantSizeRegionSplitPolicy是一個固定的值,而是會在必定條件下不斷調整,調整規則和region所屬表在當前regionserver上的region個數有關係 :(#regions) * (#regions) * (#regions) * flush size * 2,固然閾值並不會無限增大, 最大值爲用戶設置的MaxRegionFileSize。這種切分策略很好的彌補了ConstantSizeRegionSplitPolicy的短板,可以自適應大表和小表。並且在大集羣條件下對於不少大表來講表現很優秀,但並不完美,這種策略下不少小表會在大集羣中產生大量小region,分散在整個集羣中。並且在發生region遷移時也可能會觸發region分裂。
-
另外, 還有一些其餘分裂策略, 好比使用DisableSplitPolicy: 能夠禁止region 發生分裂; 而KeyPrefixRegionSplitPolicy ,DelimitedKeyPrefixRegionSplitPolicy 對 於 切 分 策 略 依 然 依 據 默 認 切 分 策 略 , 但 對 於 切 分 點 有 自 己 的 看 法 , 比 如KeyPrefixRegionSplitPolicy要求必須讓相同的PrefixKey待在一個region中。
在用法上,通常狀況下使用默認切分策略便可,也能夠在cf級別設置region切分策略,命令爲: create’table’{NAME=>‘cf’,SPLIT_POLICY=>‘org.apache.hadoop.hbase.regionserver. ConstantSizeRegionSpli
region切分策略會觸發region切分,切分開始以後的第一件事就是尋找切分點-splitpoint。全部默認切分策略,不管是ConstantSizeRegionSplitPolicy、
IncreasingToUpperBoundRegionSplitPolicy抑或是SteppingSplitPolicy,對於切分點的定義都是一致的。固然,用戶手動執行切分時是能夠指定切分點進行切分的,這裏並不討論這種狀況。
那切分點是如何定位的呢?整個region中最大store中的最大文件中最中心的一個block的首個rowkey。這是一句比較消耗腦力的語句,須要細細品味。另外,HBase還規定,若是定位到的rowkey是整個文件的首個rowkey或者最後一個rowkey的話,就認爲沒有切分點。
什麼狀況下會出現沒有切分點的場景呢?最多見的就是一個文件只有一個block,執行split的時候就會發現沒法切分。不少新同窗 在測試split的時候每每都是新建一張新表,而後往新表中插入幾條數據並執行一下flush,再執行split,奇蹟般地發現數據表並無真正執行切分。緣由就在這裏,這個時候仔細的話你翻看debug日誌是能夠看到這樣的日誌滴:
HBase將整個切分過程包裝成了一個事務,意圖可以保證切分事務的原子性。整個分裂事務過程分爲三個階段:prepare – execute– (rollback) ,操做模版以下:
1. regionserver 更改ZK節點 /region-in-transition 中該region的狀態爲SPLITING。
2. master經過watch節點/region-in-transition檢測到region狀態改變,並修改內存中region的狀態,在master頁面RIT模塊就能夠看到region執行split的狀態信息。
3.在父存儲目錄下新建臨時文件夾,split保存split後的daughter region信息。
4.關閉parent region:parent region 關閉數據寫入並觸發flush操做,將寫入region的數據所有持久化到磁盤,此後短期內客戶端落在父region上的請求都會拋出異常NotServingRegionException。
5. 核心分裂步驟:在.split文件夾下新建兩個子文件夾,稱之爲daughter A、daughter B,並在文件夾中生成reference文件, 分別指向父region中對應文件。這個步驟是全部步驟中最核心的一個環節,生成reference文件日誌以下所示: 2017-08-12 11:53:38,158 DEBUG [StoreOpene-0155388346c3c919d3f05d7188e885e0-1] regionserver.StoreFileInfo: reference'hdfs://hdfscluster/hbase-rsgroup/data/default/music/0155388346c3c919d3f05d7188e885e0/cf/d24415c4fb44427b8f698143e5c4d9dc00 其中reference文件名爲d24415c4fb44427b8f698143e5c4d9dc.00bb6239169411e4d0ecb6ddfdbacf66,格式看起來比較特殊,那這種文件名具體什麼含義呢?那來看看該reference文件指向的父region文件,根據日誌能夠看到,切分的父region是00bb6239169411e4d0ecb6ddfdbacf66,對應的切分文件是d24415c4fb44427b8f698143e5c4d9dc,可見reference文件名是個信息量很大的命名方式,以下所示:
除此以外,還須要關注reference文件的文件內容,reference文件是一個引用文件(並不是linux連接文件),文件內容很顯然不是用戶數據。文件內容其實很是簡單, 主要有兩部分構成: 其一是切分點splitkey, 其二是一個boolean類型的變量( true 或者false),true表示該reference文件引用的是父文件的上半部分(top),而false表示引用的是下半部分 (bottom)。爲何存儲的是這兩部份內容?且聽下文分解。
看官可使用hadoop命令親自來查看reference文件的具體內容: hadoopdfs-cat/hbase-rsgroup/data/default/music/0155388346c3c919d3f05d7188e885e0/cf/d24415c4fb44427b8f698 6. 父region分裂爲兩個子region後,將daughter A、daughter B拷貝到HBase根目錄下,造成兩個新的region。
7. parent region通知修改 hbase.meta 表後下線,再也不提供服務。下線後parent region在meta表中的信息並不會立刻刪除, 而是標註split列、offline列爲true,並記錄兩個子region。爲何不立馬刪除?且聽下文分解。
8. 開啓daughter A、daughter B兩個子region。通知修改 hbase.meta 表,正式對外提供服務。
Region切分事務性保證
整個region切分是一個比較複雜的過程,涉及到父region中HFile文件的切分、兩個子region的生成、系統meta元數據的更改等不少子步驟,所以必須保證整個切分過程的事務性,即要麼切分徹底成功,要麼切分徹底未開始,在任何狀況下也不能出現切分只完成一半的狀況。
爲了實現事務性,hbase設計了使用狀態機(見SplitTransaction類)的方式保存切分過程當中的每一個子步驟狀態,這樣一旦出現異常,系統能夠根據當前所處的狀態決定是否回滾,以及如何回滾。遺憾的是,目前實現中這些中間狀態都只存儲在內存中,所以一旦在切分過程當中出現regionserver宕機的狀況,有可能會出現切分處於中間狀態的狀況,也就是RIT狀態。這種狀況下須要使用hbck工具進行具體查看並分析解決方案。在2.0版本以後,HBase實現了新的分佈式事務框架Procedure V2(HBASE-12439),新框架將會使用HLog存儲這種單機事務(DDL操做、Split操做、Move操做等)的中間狀態,所以能夠保證即便在事務執行過程當中參與者發生了宕機,依然可使用HLog做爲協調者對事務進行回滾操做或者重試提交,大大減小甚至杜絕RIT現象。這也是是2.0在可用性方面最值得期待的一個亮點!!!
經過region切分流程的瞭解,咱們知道整個region切分過程並無涉及數據的移動,因此切分紅本自己並非很高,能夠很快完成。切分後子region的文件實際沒有任何用戶數據,文件中存儲的僅是一些元數據信息-切分點rowkey等,那經過引用文件如何查找數據呢?子region的數據實際在何時完成真正遷移?數據遷移完成以後父region何時會被刪掉?
1. 經過reference文件如何查找數據?
這裏就會看到reference文件名、文件內容的實際意義啦。整個流程以下圖所示:
(1)根據reference文件名(region名+真實文件名)定位到真實數據所在文件路徑。
(2)定位到真實數據文件就能夠在整個文件中掃描待查KV了麼?非也。由於reference文件一般都只引用了數據文件的一半數據, 以切分點爲界,要麼上半部分文件數據,要麼下半部分數據。那到底哪部分數據?切分點又是哪一個點?還記得上文又提到reference 文件的文件內容吧,沒錯,就記錄在文件中。
2. 父region的數據何時會遷移到子region目錄?
答案是子region發生major_compaction時,咱們知道compaction的執行其實是將store中全部小文件一個KV一個KV從小到大讀出來以後再順序寫入一個大文件,完成以後再將小文件刪掉,所以compaction自己就須要讀取並寫入大量數據。子region執行major_compaction後會將父目錄中屬於該子region的全部數據讀出來並寫入子region目錄數據文件中。可見將數據遷移放到compaction這個階段來作,是一件順便的事。
3. 父region何時會被刪除?
實際上HMaster會啓動一個線程按期遍歷檢查全部處於splitting狀態的父region,肯定檢查父region是否能夠被清理。檢測線程首先會在meta表中揪出全部split列爲true的region,並加載出其分裂後生成的兩個子region(meta表中splitA列和splitB列),只須要檢查此兩個子region是否還存在引用文件,若是都不存在引用文件就能夠認爲該父region對應的文件能夠被刪除。如今再來看看上文中父目錄在meta表中的信息,就大概能夠理解爲何會存儲這些信息了:
4. split模塊在生產線的一些坑?
有些時候會有同窗反饋說集羣中部分region處於長時間RIT,region狀態爲spliting。一般狀況下都會建議使用hbck看下什麼報錯, 而後再根據hbck提供的一些工具進行修復,hbck提供了部分命令對處於split狀態的rit region進行修復,主要的命令以下: -fixSplitParents Try to force offline split parents to be online.-removeParents Try to offline and sideline lingering parents and keep daughter regions.-fixReferenceFiles Try to offline lingering reference store files
其中最多見的問題是 : ERROR:Foundlingeringreferencefilehdfs://mycluster/hbase/news_user_actions/3b3ae24c65fc5094bc2acfebaa7a56de/ 簡單解釋一下,這個錯誤是說reference文件所引用的父region文件不存在了,若是查看日誌的話有可能看到以下異常:java.io.IOException: java.io.IOException: java.io.FileNotFoundException: File does not exist:/hbase/news_user_actions/b7
父region文件爲何會莫名其妙不存在?通過和朋友的討論,確認有多是由於官方bug致使,詳見HBASE-13331。這個jira是說HMaster在確認父目錄是否能夠被刪除時,若是檢查引用文件(檢查是否存在、檢查是否能夠正常打開)拋出IOException異常, 函數就會返回沒有引用文件,致使父region被刪掉。正常狀況下應該保險起見返回存在引用文件,保留region,並打印日誌手工介入查看。若是你們也遇到相似的問題,能夠看看這個問題,也能夠將修復patch打到線上版本或者升級版本。
網易有數:企業級大數據可視化分析平臺。面向業務人員的自助式敏捷分析平臺,採用PPT模式的報告製做,更加易學易用,具有強大的探索分析功能,真正幫助用戶洞察數據發現價值。
可點擊這裏免費試用。