作者:clark010
出處:http://www.lxweimin.com/u/f9af3f199145
版權:本文版權歸作者所有
轉載:歡迎轉載,但未經作者同意,必須保留此段聲明;必須在文章中給出原文連接;否則必究法律責任
Snapshot過程不涉及到底層數據文件的移動和拷貝,中間只會對當前snapshot所引用的文件做meta記錄,生成對應的data.manifest文件,并且SnapshotFileCache
會通過freshCache更新被snapshot引用的文件到cache中,這樣后臺的清理線程就不會將hfile清理掉,以便于后面restore恢復。
因為涉及到對一個表的所有region做snapshot操作,本質上是一個分布式操作,HBase底層實現了一套Procedure
機制支持分布式任務(包括snapshot、balance、mem flush等)??蛻舳苏埱驧aster對某一個表做snapshot,Master通發布snapshot任務到zk上并等待所有RS完成,RS接受并處理請求到最終完成請求,Master收集結果并返回最終結果給客戶端。
下面會分別分析一下Client、Master、RegionServer的代碼實現
Client
- Client調用
HBaseAdmin
的snapshot接口發起snapshot請求
-
SnapshotDescription
數據結構中最主要的是snapshot_name/table_name/type,其中type為enum類型,有三個常量:DISABLED/FLUSH/SKIPFLUSH,指定三種做snapshot的方式,第一個是對disabled的表做snapshot,后兩個是對enable的表的操作,FLUSH是snapshot之前先flush內存,SKIPFLUSH不需要flush內存
-
- 調用
taskSnapshotAsync
,向master異步提交一個snapshot請求
- 拿到response,循環等待snapshot完成,如果超過最大的timeout時間則拋
SnapshotCreationException
異常并退出,但是實際上snapshot可能還在做,并最終成功
Master
- master端接收到client端的snapshot rpc請求,調用
snapshotManager
的takeSnapshot
實際處理snapshot請求,taskSnapshot也是異步的處理邏輯,所以很快返回
- 再看
SnapshotManager
的takeSnapshot
中的邏輯-
判斷是否已經做過snapshot
-
觸發pre snapshot coprocessor邏輯
-
判斷是enabled的表還是disabled的表,對于disabled的表直接通過master做snapshot,而enabled的表則需要有RS實際完成snapshot過程,下面分別看一下兩個路徑的實現
-
disabled表snapshot
- 首先
prepareToTabkeSnapshot
,判斷是否正在做snapshot或者在restore過程,如果是則直接異常退出,否的話繼續。然后清理并創建workingDir(/<hbase-root>/.hbase-snapshot/.tmp/<snapshot-name>
) - 重置
SnapshotDescription
的type為DISABLED - 構造
TableSnapshotHandler
,其中創建SnapshotManifest
對象以及snapshot表的寫鎖(在prepare中aquire)
- 調用snapshotTable
- handler prepare,對表加寫鎖,加載table的description信息
- 將handler提交線程池分配線程執行
- 將handler加入到
snapshotHandler
中
- ok再進入table snapshot handler中看一下process執行邏輯
-
首先創建了兩個文件,.inprogress標志文件、.snapshot-info寫入本次Snapshot的desc信息
- 請求得到表的所有region信息,并對所有region進行同步的snapshot(snapshotRegions接口邏輯在
[Enabled|Disabled]TableSnapshotHandler
中實現)
- 進入
DisabledTableSnapshotHandler
中看一下snapshotRegions
的接口實現 - 實際通過
snapshotManifest
調用了region的snapshot,每個region也會在workingDir下臨時生成每個region的manifest文件
- manifest addRegion
- 創建ManifestBuilder
- 將region信息寫入manfiest
- 將family信息寫入manifest
- 將當前region的所有store file寫入manifest
- 最終調用
regionClose
將manifest內容寫出到文件中
- 看一下store file寫入manifest的邏輯,主要保存了file的name和size,如果是reference文件,則set reference標志
- reference文件會在split過程產生,在實際hfile沒有split完成時邏輯表示一個region的hfile
- reference文件會在split過程產生,在實際hfile沒有split完成時邏輯表示一個region的hfile
- 進入
- 所有region的snapshot結束后,做了三件事
-
snapshotManifest
內容寫出到data.manifest文件 - 驗證region snapshot(防止region的遷移等情況),如果不一致需要failed掉
-
將snapshot數據從.tmp路徑移動到正式路徑(.hbase-snapshot)下
-
- 到這里disabled表的snapshot流程就完成了
-
- 首先
-
enabled表snapshot
- enabled表的snapshot過程的代碼調用路徑和disabled的情況基本一致,只是在
TableSnapshotHandler
的snapshotRegions
接口的實現不一樣,下面直接從這個函數入口分析一下enabled table,對于其他的流程調用參考disabled的情況 - 可以看到enabled表通過
ProcedureCoordinator
提交了一個Procedure
任務,然后就waitForCompleted
- 在這里不具體講Procedure的邏輯,我們只需要大概的知道,hbase master通過zk和region server做交互(具體對應
ZKProcedureCoordinatorRpcs
實現),master在zk上創建具體任務的aquire根節點,并對table所有Region的RegionServer創建一個對應的znode節點并watch此node,而RegionServer上有對應的watcher(ZKProcedureMemberRpcs
)發現有任務就領取,處理結束后通過zk通知完成
- enabled表的snapshot過程的代碼調用路徑和disabled的情況基本一致,只是在
-
disabled表snapshot
-
RegionServer
通過前面的代碼分析,我們知道disabled表的snapshot直接在master端完成,而enabled表的snapshot需要RS參與并實際執行snapshot邏輯,下面分析一下snapshot在RS端的實現邏輯,同樣Procedure部分的代碼部分省略
- 首先RS接收到任務后,會先create一個
SubProcedure
- 判斷type類型是否需要flush內存,但是貌似flush和skipflush的代碼一樣,具體在
FlushSnapshotSubprocedure
中判斷
- 進入
FlushSnapshotSubprocedure
的call
方法,首先調用region的startRegionOperation
方法,對region加鎖防止數據的更新,然后判斷是否需要flush內存,最后調用HRegion的addRegionToSnapshot
方法執行實際的邏輯
- 進入
addRegionToSnapshot
方法,發現最后處理邏輯也是調用了SnapshotManifest的addRegion
方法,這和Disabled表的邏輯就匯合一致了,其實EnabledTableSnapshot要分布式的通過RS完成還是為了對region加鎖的一個操作……
結語
OK,到這里基本Snapshot的整個流程就分析完了,雖然沒有詳細到分析到具體data.manifest文件的格式,但是主要把握住大的邏輯,小邏輯就靠后面細細的看代碼了,也許后面有精力也會單獨加一章分析data.manifest的格式