HBase RegionServer宕機處理恢復


  本文分析RegionServer宕機后這個region server上的region是如何在其他region server上恢復的。

region server宕機后發生了什么  

  HMaster有一個RegionServerTracker對象,監控zk上/hbase/rs目錄下的結點,達到監控region server下線的目的。一個region server宕機后,zk上相應結點刪除,觸發RegionServerTracker的nodeDeleted(),方法調用ServerManager的expireServer邏輯,對於非meta region(0.96后只有一個meta region),提交一個ServerShutdownHanlder的任務給內部線程池處理,任務的處理邏輯在handler的process()中。HBASE-7006引入了distributed log replay特性,這里以distributed log replay為例。如果開啟了distributed log replay特性,那么在zk上建立一系列結點/hbase/recovering-regions/regionEncodeName/serverName,其中regionEncodeName結點內容為該region的last flush sequence id,即這個sequence id之前的所有數據都已經flush到磁盤上產生了HFile文件,這部分數據不需要進行回放。serverName結點的內容為宕機的region server上的last flushed sequence id,即所有region中最大的last flush sequence id。將宕掉server上的region assign通過round robin的方式assign其他的活着的region server,然后提交一個LogReplayHandler的任務給內部線程池,這個任務內部就是進行split log的准備工作,將hdfs上該region server的log改名,加上-splitting后綴,變成hbase.rootdir/WALs/serverName-splitting,然后進入HMaster的SplitLogManager管理范圍,在zk上建立節點,路徑/hbase/splitWAL/對上面改寫后的log路徑的encode。然后HMaster等待log被其他region server上的SplitLogWorker split完成,然后將一開始建立的一系列節點/hbase/recovering-regions/regionEncodeName/serverName刪掉,然后將-splitting目錄刪除.

regionserver上的SplitLogWorker會不斷的去監控zk上的hbase.rootdir/WALs/serverName-splitting節點,並且試圖own這個節點.成功后,則給SplitLogWorker內部線程池提交一個HLogSplitterHandler任務,任務邏輯在對象splitTaskExecutor中,任務內部主要調用HLogSplitter.splitLogFile(),從而進到HLogSplitter的boolean splitLogFile(FileStatus logfile, CancelableProgressable reporter) throws IOException. 該函數內部會讀-splitting目錄內部的hlog文件,然后將每條log entry加入到一個sink中,sink是一個抽象類,根據是否配置使用distributed log replay,使用不同的子類,對於distributed log replay來說,使用LogReplayOutputSink,否則使用LogRecoveredEditsOutputSink。回到函數boolean splitLogFile(FileStatus logfile, CancelableProgressable reporter) throws IOException,函數的邏輯主要是從hlog中解析出一條條的log entry,如果log entry的sequence id比zk上相應的/hbase/recovering-regions/regionEncodeName 節點記錄的sequence id小,那么說明這條log entry對應的內容已經持久化在HFile中,不需要進行回放,否則將這條日志append到成員EntryBuffers對象中,EntryBuffers內部會對log entry按照region進行分組,同一個Region的log entry記錄在對象RegionEntryBuffer中。同時,會有一些寫線程,不斷的從EntryBuffers中取出RegionEntryBuffer對象,將其append到sink中,在這里,是LogReplayOutputSink。LogReplayOutputSink中積攢到一批日志,會調用WALEditsReplaySink的replayEntries()方法,通過ReplayServerCallable這個rpc發給這個region被assign后的新的region server讓其回放,由於這里使用多個寫線程給其他的region server發送日志,所以叫作distributed log replay。

非distributed log replay的模式下,LogRecoveredEditsOutputSink的工作是直接按照region,把相對應的log寫到hdfs的 hbase.rootdir/data/namespace(比如test)/table_name/region_encoded_name/recovered.edits下。后續region被其他region server open時,會來這看是不是有需要回放的hlog.

需要注意的是,在distributed log replay模式下,region是被open后,然后才replay ,可以看到open成功后,這個region可以提供寫,但是不能提供讀,因為數據不全。

以上是region server宕機后,觸發的HMaster和其他region server的邏輯。

下面看看region server 收到HMaster的open region指令的邏輯。

Open Region

如果是distributed log replay,那么會去zk上找 /hbase/recovering-regions/regionEncodeName/serverName,將region記錄在map recoveringRegions中。然后如果不是meta region,則提交一個OpenRegionHandler任務到內部線程池中,任何的邏輯主要是open region,代碼在openHRegion(final CancelableProgressable reporter),最后主要代碼在initializeRegionInternals()內部調用initializeRegionStores()方法中。這個方法主要就是從hdfs中load region對應的HFile文件,並且如果region目錄下的recovered.edits有hlog文件需要回放,則進行回放(方法replayRecoveredEditsIfAny)。

加載HFile過程中很重要的一點是,需要將這個HRegion下的所有的HStore(一個column family對應一個HStore,一個HStore下面有多個HFile和一個memstore)中最大的memstoreTS拿出來,加1后去初始化HRegion內部的mvcc對象,這個對象用於負責實現MVCC。這個時間戳相當於事物ID,用來判斷數據是否對某事務可見。

參考資料

hbase-server-0.98.3-hadoop2.jar

https://issues.apache.org/jira/browse/HBASE-7006

http://blog.cloudera.com/blog/2012/07/hbase-log-splitting/ 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM