HBase compaction 分析

Hbase爲了防止小文件(被刷到磁盤的menstore)過多,保證查詢效率,HBase需要在必要的時候將這些小的store file合併成相對較大的store file,這個過程就稱之爲compaction。在HBase中,主要存在兩種類型的compaction:minor compaction和major compaction。

   major compaction 的功能是將所有的store file合併成一個,觸發major compaction的可能條件有:major_compact 命令、majorCompact() API、region server自動運行(相關參數:hbase.hregion.majoucompaction 默認爲24 小時、hbase.hregion.majorcompaction.jetter 默認值爲0.2 防止region server 在同一時間進行major compaction)。hbase.hregion.majorcompaction.jetter參數的作用是:對參數hbase.hregion.majoucompaction 規定的值起到浮動的作用,假如兩個參數都爲默認值24和0,2,那麼major compact最終使用的數值爲:19.2~28.8 這個範圍。

   minor compaction的運行機制要複雜一些,它由一下幾個參數共同決定:

   hbase.hstore.compaction.min :默認值爲 3,表示至少需要三個滿足條件的store file時,minor compaction纔會啓動

   hbase.hstore.compaction.max 默認值爲10,表示一次minor compaction中最多選取10個store file

   hbase.hstore.compaction.min.size 表示文件大小小於該值的store file 一定會加入到minor compaction的store file中

   hbase.hstore.compaction.max.size 表示文件大小大於該值的store file 一定會被minor compaction排除

   hbase.hstore.compaction.ratio 將store file 按照文件年齡排序(older to younger),minor compaction總是從older store file開始選擇,如果該文件的size 小於它後面hbase.hstore.compaction.max 個store file size 之和乘以 該ratio,則該store file 也將加入到minor compaction 中。

Compaction是buffer->flush->merge的Log-Structured Merge-Tree模型的關鍵操作,主要起到如下幾個作用:

1)合併文件

2)清除刪除、過期、多餘版本的數據

3)提高讀寫數據的效率

Minor & Major Compaction的區別

1)Minor操作只用來做部分文件的合併操作以及包括minVersion=0並且設置ttl的過期版本清理,不做任何刪除數據、多版本數據的清理工作。

2)Major操作是對Region下的HStore下的所有StoreFile執行合併操作,最終的結果是整理合並出一個文件。

從這個功能上理解,Minor Compaction也不適合做Major的工作,因爲部分的數據清理可能沒有意義,例如,maxVersions=2,那麼在少部分文件中,是否是kv僅有的2個版本也無法判斷。

在什麼情況下會發生Compaction呢?

參數名 配置項 默認值
minFilesToCompact hbase.hstore.compactionThreshold 3
maxFilesToCompact hbase.hstore.compaction.max 10
maxCompactSize hbase.hstore.compaction.max.size Long.MAX_VALUE
minCompactSize hbase.hstore.compaction.min.size memstoreFlushSize

在執行壓縮檢查時,系統自動決定運行那種合併。在memstore被刷寫到磁盤後會觸發檢查,或在Shell命令compact、major_compact之後觸發檢查,或者是相應API在被調用後觸發檢查,抑或是被一個異步的後臺進程觸發。region服務器運行這個線程,而其功能由CompactionChecker類實現。

CompactionChecker是RS上的工作線程(Chore),執行週期是通過threadWakeFrequency指定,大小通過Hbase.server.thread.wakefrequency配置(默認10000),然後乘以默認倍數multiple(1000),毫秒時間轉換爲秒。因此,在不做參數修改的情況下,CompactionChecker大概是2hrs, 46mins, 40sec執行一次。

首先,對於HRegion裏的每個HStore進行一次判斷,needsCompaction()判斷是否足夠多的文件觸發了Compaction的條件。

條件爲:HStore中StoreFiles的個數 – 正在執行Compacting的文件個數 > minFilesToCompact

操作:以最低優先級提交Compaction申請。

步驟1:選出待執行Compact的storefiles。由於在Store中的文件可能已經在進行Compacting,因此,這裏取出未執行Compacting的文件,將其加入到Candidates中。

步驟2:執行compactSelection算法,在Candidates中選出需要進行compact的文件,並封裝成CompactSelection對象當中。

1) 選出過期的store files。過濾minVersion=0,並且storefile.maxTimeStamp + store.ttl < now_timestamp。這意味着整個文件最大的時間戳的kv,都已經過期了,從而證明整個storefile都已經過期了。CompactSelection如果發現這樣的storefile,會優先選擇出來,作爲Min然後提交給Store進行處理。

 這部分具體操作被封裝在ScanQueryMatcher下的ColumnTracker中,在StoreScanner的遍歷過程,ScannerQueryMatcher負責kv的過濾。這裏的ScanType包括(MAJOR_COMPACT,MINOR_COMPACT,USER_SCAN),compact操作是對選出的文件執行一次標識ScanType爲MAJOR_COMPACT或者MINOR_COMPACT類型的scan操作,然後將最終符合標準的kv存儲在一個新的文件中。

參考設置:根據應用的需求設置ttl,並且設置minVersions=0,根據selectCompation優選清理過期不保留版本的文件的策略,這樣會使得這部分數據在CompactionChecker的週期內被清理。

誤區:在CompactSplitThread有兩個配置項

hbase.regionserver.thread.compaction.large:配置largeCompactions線程池的線程個數,默認個數爲1。

hbase.regionserver.thread.compaction.small:配置smallCompactions線程池的線程個數,默認個數爲1。

這兩個線程池負責接收處理CR(CompactionRequest),這兩個線程池不是根據CR來自於Major Compaction和Minor Compaction來進行區分,而是根據一個配置hbase.regionserver.thread.compaction.throttle的設置值(一般在hbase-site.xml沒有該值的設置),而是採用默認值2 * minFilesToCompact * memstoreFlushSize,如果cr需要處理的storefile文件的大小總和,大於throttle的值,則會提交到largeCompactions線程池進行處理,反之亦然。

參考設置:可以稍微調大一些largeCompactions和smallCompactions線程池內線程的個數,建議都設置成5。

2) 判斷是否需要進行majorCompaction,這是很多判斷條件的合成,其中最爲重要的一個是
hbase.hregion.majorcompaction設置的值,也就是判斷上次進行majorCompaction到當前的時間間隔,如果超過設置值,則滿足一個條件,同時另外一個條件是compactSelection.getFilesToCompact().size() < this.maxFilesToCompact。

因此,通過設置hbase.hregion.majorcompaction = 0可以關閉CompactionChecke觸發的major compaction,但是無法關閉用戶調用級別的mc。

3) 過濾對於大文件進行Compaction操作。判斷fileToCompact隊列中的文件是否超過了maxCompactSize,如果超過,則過濾掉該文件,避免對於大文件進行compaction。

4) 如果確定Minor Compaction方式執行,會檢查經過過濾過的fileToCompact的大小是否滿足minFilesToCompact最低標準,如果不滿足,忽略本次操作。確定執行的Minor Compaction的操作時,會使用一個smart算法,從filesToCompact當中選出匹配的storefiles。
具體算法爲:

如果fileSizes[start] > Math.max(minCompactSize, (long)(sumSize[start+1]*r ),那麼繼續start++。這裏r的含義是compaction比例,它有如下四個參數控制:

配置項 默認值 含義
hbase.hstore.compaction.ratio 1.2F
hbase.hstore.compaction.ratio.offpeak 5.0F 與下面兩個參數聯用
hbase.offpeak.start.hour -1 設置hbase offpeak開始時間[0,23]
hbase.offpeak.end.hour -1 設置hbase offpeak結束時間 [0,23]

如果默認沒有設置offpeak時間的話,那麼完全按照hbase.hstore.compaction.ration來進行控制。如下圖所示,如果filesSize[i]過大,超過後面8個文件總和*1.2,那麼該文件被認爲過大,而不納入minor Compaction的範圍。

這裏寫圖片描述

這樣做使得Compaction儘可能工作在最近刷入hdfs的小文件的合併,從而使得提高Compaction的執行效率。

5) 通過selectCompaction選出的文件,加入到filesCompacting隊列中。

6) 創建compactionRequest,提交請求。

總結:

在大多數情況下,Major是發生在storefiles和filesToCompact文件個數相同,並且滿足各種條件的前提下執行。這裏進行幾個參數配置的簡介:

hbase.hregion.majorcompaction: 設置系統進行一次MajorCompaction的啓動週期,如果設置爲0,則系統不會主動觸發MC過程。

hbase.hstore.compaction.max:設置執行Compaction(包括Major &Minor)的待合併文件的最大個數。默認值爲10,如果超過該設置值,會對部分文件執行一次MinorCompaction,選擇算法如Figure1。

hbase.hstore.compactionThreshold: 設置執行Compaction(Major && Minor)操作的閾值,默認是3,如果想降低過頻繁的合併操作,可以稍微調大一點,對於HBase負載較重的系統,可以設置成5。

Compaction對於讀寫操作的影響

Compaction與Flush不同之處在於:Flush是針對一個Region整體執行操作,而Compaction操作是針對Region上的一個Store而言,因此,從邏輯上看,Flush操作粒度較大。這屬於一個LSM存儲模型最核心的設計:

1)Flush操作如果只選擇某個Region的Store內的MemStore寫入磁盤,而不是統一寫入磁盤,那麼HLog上key的一致性在Reigon不同ColumnFamily(Store)下的MemStore內就會有不一致的key區間。

如下圖所示,我們假定該RegionServer上僅有一個Region,由於不同的Row是在列簇上有所區別,就會出現有些不同Store內佔用的內存不一致的情況,這裏會根據整體內存使用的情況,或者RS使用內存的情況來決定是否執行Flush操作。如果僅僅刷入使用內存較大的memstore,那麼在使用的過程中,一是Scan操作在執行時就不夠統一,二是在HLog Replayer還原Region內Memstore故障前的狀態,只需根據Hlog的Flush_marker的標記位來執行Replay即可。

這裏寫圖片描述

2)Compaction執行結束之後會生成臨時文件,臨時文件所在的hdfs位置如下:

/hbase-comp/comp_cluster/ffd87a50c3df3080183d4910d183d0ee/.tmp

ffd87a50c3df3080183d4910d183d0ee 是comp_cluster表格的Region名。臨時文件的意義在於,在Compaction執行期間,對於原數據訪問沒有影響。Compaction執行合併操作生成的文件生效過程,需要對Store的寫操作加鎖,阻塞Store內的更新操作,直到更新Store的storeFiles完成爲止。(注意,這個操作過程執行會影響到更新服務,但是影響不會太大)

3)對於讀服務的影響,類似於Flush操作,也是通過ChangedReaderObserver爲StoreScanner註冊監聽類來實現的。具體內容可以參考之前的”HBase Flush操作流程以及對讀寫服務的影響”。

發佈了87 篇原創文章 · 獲贊 50 · 訪問量 23萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章