天天看點

HBase源碼分析之HRegion上MemStore的flsuh流程(一)

        了解HBase架構的使用者應該知道,HBase是一種基于LSM模型的分布式資料庫。LSM的全稱是Log-Structured Merge-Trees,即日志-結構化合并-樹。相比于Oracle普通索引所采用的B+樹,LSM模型的最大特點就是,在讀寫之間采取一種平衡,犧牲部分讀資料的性能,來大幅度的提升寫資料的性能。通俗的講,HBase寫資料如此快,正是由于基于LSM模型,将資料寫入記憶體和日志檔案後即立即傳回。

        但是,資料始終在記憶體和日志中是不妥當的,首先記憶體畢竟是有限的稀缺資源,持續的寫入會造成記憶體的溢出,而日志的寫入僅是由于記憶體資料系統當機或程序退出後立刻消失而采取的一種保護性措施,而不是作為最終的資料持久化。日志檔案不能用來做最終持久化的另外一個原因,就是寫入日志時僅僅是簡單的追加(append),讀資料時效率會非常非常的低。

        MemStore的flush就是為了解決上述問題而采取的一種有效措施。關于B+樹、LSM模型,讀者可自行補腦。本文僅僅闡述HRegion上MemStore的flsuh流程,而關于何時發生flush等其他内容将在其他的博文中進行分析。

        說了這麼多,下面,就開始神奇的源碼分析之旅吧~

        先從宏觀上對HRegion上fMemStore的flush流程有一個整體的把握。HRegion上flush的入口方法為flushCache(),其處理整體流程如圖所示:

HBase源碼分析之HRegion上MemStore的flsuh流程(一)

        下面,我們看下HRegion上flushCache()方法,代碼如下:

        通過代碼我們可以知道,其處理邏輯如下:

        1、首先需要判斷下HRegion的狀态,如果Region正處于關閉狀态,記錄日志,并傳回CANNOT_FLUSH的重新整理結果;

        ps:這是大資料諸多架構,比如HDFS、HBase、Spark等絕大多數内部處理流程采取的一種通用的模式,判斷涉及到的實體,比如HRegion、DataNode、DataXceiveServer等的狀态,比如正在關閉closing、已經關閉closed等,目的是協調各實體協同工作,保障本處理流程是真實有效的。

        2、擷取任務追蹤器,并建立初始狀态:Flushing ****HRegion,初始化後的狀态對象為MonitoredTask類型的status;

        3、設定任務追蹤器的狀态:請求Region讀鎖:Acquiring readlock on region;

        4、擷取Region的讀鎖,阻塞等待重新整理緩存的鎖釋放;

        5、再次判斷HRegion的狀态,如果Region已經下線,記錄日志并傳回CANNOT_FLUSH的結果;

        6、如果協處理器不為空:

              6.1、設定任務追蹤器的狀态:執行協處理器預刷寫鈎子preFlush()方法:Running coprocessor pre-flush hooks;

              6.2、執行協處理器預刷寫鈎子preFlush()方法;

        7、如果writestate不是flushing,且writestate的可以讀取啟用,将狀态中的flushing設定為true,表示正在重新整理,否則記錄日志,并傳回CANNOT_FLUSH的結果;

        8、調用internalFlushcache()方法,執行真正的flush;

        9、重新整理結束後,如果協處理器不為空,設定狀态,即Running post-flush coprocessor hooks,并執行協處理器的鈎子方法postFlush();

        10、狀态追蹤器标記完成狀态:Flush successful;

        11、将writestate中的flushing、flushRequested均設定為false;

        12、釋放讀鎖,并清空狀态追蹤器的狀态;

        13、傳回重新整理結果。

        至此,HRegion上MemStore的flush流程全部完畢,其中internalFlushcache()是其真正執行flush的核心方法,關于這部分我們将在下一篇文章中講解。在此,隻是概括下外圍的整體流程。

        關于上述流程,有以下幾點需要單獨說明下:

        1、關于closing和closed标志位狀态的判斷

        HRegion中,有兩個關于關閉的狀态标志位成員變量,分别定義如下:

        為什麼需要兩個狀态标志位呢?我麼知道,Region下線關閉時,需要處理一些諸如flush等的操作,是以一般比較耗時,那麼在其下線關閉期間,我們不希望該Region再執行flsuh、compact等請求,是以,我們就需要兩個标志位,一個表示正在關閉過程的closing,另外一個是已經關閉的closed。是以,flush、compact等流程的執行,都會去判斷這兩個狀态位,確定flush和compact允許被執行。

        2、關于讀寫鎖的使用

        HRegion中,保持了兩把鎖,分别定義如下:

        這兩個鎖均為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的寫鎖。

        3、關于寫狀态WriteState的使用

        再來說下HRegion的另外一個成員變量writestate,它是HRegion的内部類WriteState類型的,這個類是一種協調重新整理、合并與關閉操作的非常使用的資料結構。它的關鍵成員變量定義如下:

        其中,當一個flush發生或者正在進行時,flushing會被設定為true,而當一個flush請求發生時,flushRequested被設定為true。另外,還包含了合并進行的數目compatcing、可寫狀态writesEnabled、可讀狀态readsEnabled和隻讀狀态readOnly等。

        為什麼要用這麼一個資料結構來表示Region的狀态呢?我們知道,HRegion代表了HBase表中按行切分的區域,在HRegion上,可能存在flush、compact等多種操作,使用單一的操作并不能很好的表達出HRegion的狀态,是以作者構思出這麼一個資料結構,協調fulsh、compact及其HRegion讀寫等狀态。

       好了,期待下一篇關于flush核心流程的介紹吧!

繼續閱讀