直接進入主題吧,上代碼。
從代碼上看得出來,啟用的表和被禁用的表走的是兩個不同的方法。
先看snapshotenabledtable方法吧,看看線上的表是怎麼備份的。
這裡就兩步,先去看看snapshot前的準備工作吧,f3進入preparetotakesnapshot方法。這個方法裡面也沒幹啥,就是檢查一下是否可以對這個表做備份或者恢複的操作,然後就會重建這個工作目錄,這個工作目錄在.hbase-snapshot/.tmps下面,每個snapshot都有自己的目錄。
在snapshottable裡面把就線程送出一下,讓handler來處理了。
這些都不是重點,咱到handler那邊去看看吧,enabledtablesnapshothandler是繼承takesnapshothandler的,prepare方法和process方法都一樣,差別在于snapshotregions方法被重寫了。
看prepare方法還是檢查表的定義檔案在不在,我們直接進入process方法吧。
1、寫一個.snapshotinfo檔案到工作目錄下
2、把表的定義資訊寫一份到工作目錄下,即.tabledesc檔案
3、查找和表相關的region server和機器
4、開始備份
5、檢驗snapshot的結果
6、确認沒問題了,就把臨時目錄rename到正式目錄
我們直接到備份這一步去看吧,方法在enabledtablesnapshothandler裡面,重寫了。
這裡用到一個分布式事務,這裡被我叫做分布式事務,我也不知道它是不是事務,但是procedure這個詞我真的不好翻譯,叫過程也不合适。
我們進入procedurecoordinator的startprocedure看看吧。
先建立procedure,然後送出它,這塊沒什麼特别的,繼續深入進去submitprocedure方法也找不到什麼有用的資訊,我們得回到procedure類裡面去,它是一個callable的類,奧秘就在call方法裡面。
從sendglobalbarrierstart開始看吧,裡面就一句話。
再追殺下去。
1、首先是檢查abortnode ,什麼是abortnode ?每個procname在zk下面都有一個對應的節點,比如snapshot,然後在procname下面又分了acquired、reached、abort三個節點。檢查abort節點下面有沒有目前的執行個體。
2、在acquired節點為該執行個體建立節點,建立執行個體節點的時候,把snapshotdescription的資訊(在enabledtablesnapshothandler類裡面通過this.snapshot.tobytearray()傳進去的)放了進去,建立完成之後,在該執行個體節點下面監控各個region server的節點。如果發現已經有了,就更新procedure中的acquiringmembers清單和inbarriermembers,把節點從
acquiringmembers中删除,然後添加到inbarriermembers清單當中。
3、到這一步服務端的工作就停下來了,等到所有rs接收到指令之後通過執行個體節點當中儲存的表資訊找到相應的region建立子過程,子過程在acquired節點下建立節點。
4、收到所有rs的回複之後,它才會開始在reached節點建立執行個體節點,然後繼續等待。
5、rs完成任務之後,在reached的執行個體節點下面建立相應的節點,然後回複。
6、在确定所有的rs都完成工作之後,清理zk當中的相應proname節點。
<b>注意:</b>在這個過程當中,有任務的錯誤,都會在abort節點下面建立該執行個體的節點,rs上面的子過程一旦發現abort存在該節點的執行個體,就會取消該過程。
snapshot這塊在region server是由regionserversnapshotmanager類裡面的procedurememberrpcs負責監測snapshot下面的節點變化,當發現acquired下面有執行個體之後,啟動新任務。
這塊折疊起來,不是咱們的重點,讓大家看看而已。我們直接進入subprocedure這個類裡面看看吧。
insidebarrier的實作在flushsnapshotsubprocedure這個類裡面,調用了flushsnapshot(),這個方法給每個region都開一個線程去送出。
我們接下來看看regionsnapshottask的call方法。
在對region操作之前,先上鎖,不讓讀了。然後就flushcache,這個方法很大,也好難懂哦,不過我們還是要迎接困難上,我折疊起來吧,想看的就看,不想看的就看我下面的寫的步驟吧。
1、擷取wal日志的flushid(要寫入到hfile當中,以後恢複的時候,要拿日志的flushid和hfile的flushid對比,小于hfile的flushid的就不用恢複了)
2、給memstore的做snapshot,從kvset集合轉移到snapshot集合
3、同步日志,寫入到硬碟
5、上一步的生成的檔案是儲存在臨時目錄中的,轉移到正式的目錄當中
6、更新memstore當中的大小
好,我們繼續看addregiontosnapshot方法,好累啊,尼瑪,這麼多步驟。
在工作目錄在.hbase-snapshot/.tmps/snapshotname/region/familyname/下面給hfile建立引用檔案。在建立引用檔案的時候,還要先判斷一下這個所謂的hfile是不是真的hfile,還是它本身就是一個引用檔案了。
如果已經是引用檔案的話,把舊的引用檔案裡面的内容寫入到新的引用檔案當中。
如果是一個正常的hfile的話,就建立一個空的引用檔案即可,以後我們可以通過它的名字找到它在snapshot下面相應的檔案。
okay,到這裡,每個rs的工作都完成了。
完成執行分布式事務,就是備份split過的region了,把之前的代碼再貼一次吧,折疊起來,需要的自己看。
備份啟用的表,現在已經結束了,但是備份禁用的表吧,前面說了差別是snapshotregions方法,但是方法除了做一些準備工作之外,就是snapshotdisabledregion。。。。是以snapshot到這裡就完了,下面我們<b>再回顧一遍吧</b>。
1、進行snapshot之前的準備,建立目錄,複制一些必要的資訊檔案等。
2、對于啟用的表,啟動分布式事務,rs接到任務,flush掉wal日志和memstore的資料,寫入檔案。
3、為hfile建立引用檔案,這裡的引用檔案居然是空的檔案,而且名字一樣,它不是真的備份hfile,這是什麼回事呢?這個要到下一章,從snapshot中恢複,才能弄明白了,這個和hbase的歸檔檔案機制有關系,hbase删除檔案的時候,不是直接删除,而是把它先放入archive檔案夾内。