Compaction介绍
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個版本也無法判斷。
下面是引用:
There are two types of compactions: minor and major. Minor compactions will usually pick up a couple of the smaller adjacent StoreFiles and rewrite them as one. Minors do not drop deletes or expired cells, only major compactions do this. Sometimes a minor compaction will pick up all the StoreFiles in the Store and in this case it actually promotes itself to being a major compaction.
After a major compaction runs there will be a single StoreFile per Store, and this will help performance usually. Caution: major compactions rewrite all of the Stores data and on a loaded system, this may not be tenable; major compactions will usually have to be done manually on large systems.
Compaction誘發因子
在什么情況下會發生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 |
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的范圍。
Figure 1 Minor Compaction File Selection Algorithm
這樣做使得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-weibo/bi_weibo_cluster/ffd87a50c3df3080183d4910d183d0ee/.tmp
ffd87a50c3df3080183d4910d183d0ee
是bi_weibo_cluster表格的Region名。臨時文件的意義在于,在Compaction執行期間,對于原數據訪問沒有影響。
Compaction執行合并操作生成的文件生效過程,需要對Store的寫操作加鎖,阻塞Store內的更新操作,直到更新Store的
storeFiles完成為止。(注意,這個操作過程執行會影響到更新服務,但是影響不會太大)
3)對于讀服務的影響,類似于Flush操作,也是通過ChangedReaderObserver為StoreScanner注冊監聽類來實現的。具體內容可以參考之前的”HBase Flush操作流程以及對讀寫服務的影響”。
總結
以上是生活随笔為你收集整理的Compaction介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: sql优化之(DMV)
- 下一篇: iOS pods集成与使用介绍