天天看點

Hbase Memstore 讀寫及 flush 源碼分析

本文檔主要從源碼的角度分析了,hbase的寫緩存的讀寫以及flush過程。因為在分析wal的過程中已經把寫分析的比較詳盡了,而因為memstore是記憶體結構讀的過程比較簡單,本文檔概要說明memstore的讀寫,着重分析flush過程。

1.準備工作,主要是和Coprocessor相關

2.獲得行鎖,把所有要更新的行鎖都拿到通過getRowLockInternal(byte[] row, boolean waitForLock),這個方法會在每個鎖上都輪詢一直拿到所有row的鎖。

有關原理可以參考:

http://blog.csdn.net/lipeng_bigdata/article/details/50458771

3.獲得region的update鎖,具體的說是java.util.concurrent.locks包中ReentrantReadWriteLock的讀鎖。

HRegion中聲明了兩個鎖,分别是lock和updatelock,這裡解釋下。這兩個鎖均為ReentrantReadWriteLock類型的讀寫鎖,其中,lock用于Region的close、compact、flush等的并發控制,它控制的是Region的整體行為,更具體的,compact()和flushCache()方法中,用的是lock的讀鎖--共享鎖,而doClose()方法中,用的是lock的寫鎖--獨占鎖,這也就意味着,在Region下線,執行doClose()方法時,它必須等待compact()和flushCache()方法調用完,且一旦它獲得了lock的寫鎖,後續Region将不會再執行Region的compact和flush,當然,doClose()内部仍然會在下線前flush掉它的memstore,同時共享鎖業也實作了Region的flush和compact在理論上可以同時進行。而updatesLock則用于Region資料更新方面,在flush的核心方法internalFlushcache()中,則是使用的updatesLock的寫鎖。

doProcessRowWithTimeout-》讓 processor(MultiRowMutationProcessor 用于執行多個 put/delete)掃描rows,生成mutations和waledits。(Let the processor scan the rows, generate mutations and add waledits)

主要是檢查cf并生成時間戳并把同一行的更新Cell放到一個WALEdit中。

這裡又生成一個mutations的原因是區分put和delete

6.mvcc 開始處理,也即是把通過生成的mvccId生成寫Id并把目前cell放入mvcc的寫隊列。hbase的mvcc機制将結合行鎖在後面的hbase效率的源碼分析中具體分析。可先參考:

http://m.blog.csdn.net/article/details?id=43836701

7.預處理

8.和memstore應用的相關,周遊mutations,通過getStore獲得HStore執行個體,把這些cell添加到store中。memstore中根據不同的CF對應了不同的HStore執行個體,HStore執行個體又對應了多個HFile。memstore的實際記憶體映射就是這些HStore。

8.append到Hlog中,準确的應該是append到RingBuffer中。詳見WAL的文章

9.釋放region的update鎖,即3中獲得的鎖。

10.釋放所有的row鎖,即2中獲得的鎖。

11.同步editlog,準确的說是通知RingBuffer。

調用完成了Put的回調

-------------------->寫的過程中通過調用requestFlush()方法來進行memstore的刷寫。

調用所在RegionServer的MemStoreFlusher。requestFlush方法進行刷寫。

hbase的讀需要從要讀三個位置,blockcache、memstore和hfile着手。

大概過程是先從blockcache中讀,如果沒有則去memstore和hfile中去讀,先用布隆過濾器把一定不可能的hfile去除,再使用scanner按時間降序掃描到需要的keyvalues,最後把相應塊加到blockcache中去并發還給client端。

因為包括了整個讀過程。

原理參考:

http://hbasefly.com/2016/12/21/hbase-getorscan/

http://blackproof.iteye.com/blog/2007981

和《權威指南》P327

http://hbasefly.com/2016/04/26/hbase-blockcache-2/

接下來分析本文檔的重點:

從memstore刷寫時機(上一篇文檔着重叙述)來看,有六種情況:單個memstore,一個region中,整個regionserver,Hlog,定期,和人工。

盡管觸發memstore的條件很多,但實際執行memstore的flush是調用對應的HRegion的flushcache方法開始的。它的原型如下:

Hbase Memstore 讀寫及 flush 源碼分析

調用這個方法,隻有在cache(memstore)為空,region已經關閉,目前flush正在進行和不能寫情況下。

其調用基本過程如下:

Hbase Memstore 讀寫及 flush 源碼分析

其中flushcache()和internalFlushcache都是HRegion中的方法。

1.最開始flushcache會使用HRegion用于應對region并發控制的lock(前面有介紹)加鎖。2.然後使用synchronize獲得WriteState結構的狀态,這個類主要用于保證Region級别的flush、compact時的狀态一緻。即是說有多個線程調用flushcache時,先獲得這個對象的去flush。3.擷取需要去flush的HStore,如果參數forceFlushAllStores為true的話,就會flush目前region上的所有stores,如果為false的話,根據配置的FlushPolicy(hbase.regionserver.flush.policy,預設是FlushLargeStoresPolicy)選擇部分stores來flush。

然後調用internalFlushCache方法,這個方法實際去執行,選擇一些stores到hfile(圖中藍色部分)。當刷寫成功後将标記成功的memstore,并通知因writeState而阻塞的線程。最後釋放lock。

Hbase Memstore 讀寫及 flush 源碼分析

在internalFlushCache方法中把flush memstore分成兩部分,第一部分是準備(interPrepareFlushCache):主要是去準備一些中間資料結構和以及目前memstore的快照,這個快照的作用是在flush memstore的同時并不妨礙client對memstore的讀寫;第二部分是把快照刷寫到一個臨時目錄中,然後再把臨時目錄中資料移到正式目錄,要把具體的刷寫分成這兩步的就像是兩階段送出,刷寫到臨時目錄就是确認過程而後一步就是送出過程。

我們知道hbase通過精心的設計成一個以順序寫見長的資料存儲系統,而memstore刷寫時的快照即是其中精心設計的部分。原理其實很簡單,為了不中斷讀寫,在prepare部分,建立一個新的memstore(HStore)并把相關名額清零,舊的memstore就作為快照刷入HFile。因為memstore都是記憶體操作,是以這個轉換是很快的。當然在轉換的過程中,update的操作會被暫停一段時間。

prepare部分另一個中間資料結構分别為:totalFlushableSizeOfFlushableStores,storeFlushCtxs,committedFiles,storeFlushableSize,比較重要的是storeFlushCtxs和committedFiles。他們都被定義為以CF做key的TreeMap,分别代表了store的CF實際執行(StoreFlusherImpl)和最終刷寫的HFlile檔案:

Hbase Memstore 讀寫及 flush 源碼分析
Hbase Memstore 讀寫及 flush 源碼分析

StoreFlusherImpl是HStore的内部類,它實作了StoreFlushContext的prepare,flushCache以及commit方法,這幾個方法用于完成準備和刷寫HStore的操作。其類圖如下:

Hbase Memstore 讀寫及 flush 源碼分析

在第二部分的internalFlushCacheAndCommit刷寫Hfile到臨時目錄和轉到正式目錄就比較清晰了,使用兩階段送出直接調用StoreFusherImpl的flushCache和commit方法。

Hbase Memstore 讀寫及 flush 源碼分析
Hbase Memstore 讀寫及 flush 源碼分析

稍微需要注意的是,在flush的時候有可能會失敗,這時候意味着memstore未被持久化,則wal需要去重做,會啟動一個單獨且唯一的線程去做這個,從源碼注釋上看,目前隻有regionserver重新開機會發生這種事情。

Hbase Memstore 讀寫及 flush 源碼分析

至此,memstore的讀寫已經刷入源碼分析就結束了,可以看到memstore作為hbase寫緩存為了實作快速順序寫做出的設計努力。下一篇文檔将分析哪些情況下memstore會被刷寫。