本套技術專欄是作者(秦凱新)平時工作的總結和昇華,通過從真實商業環境抽取案例進行總結和分享,並給出商業應用的調優建議和叢集環境容量規劃等內容,請持續關注本套部落格。版權宣告:禁止轉載,歡迎學習。QQ郵箱地址:1120746959@qq.com,如有任何學術交流,可隨時聯絡。
網上的Hbase調優資料參差不齊,實在是不忍卒讀,有些都是拼湊且版本過時的東西,我這裡決定綜合所有優質資源進行整合,寫一份最全,最有深度,不過時的技術部落格。辛苦成文,各自珍惜,謝謝!版權宣告:禁止轉載,歡迎學習
1 HFile合併(定址風波 => 萬物歸一)
- HFile畢竟儲存在硬碟上,那麼涉及到讀操作就涉及:定址。當HFile檔案一多,那麼每次讀取資料的時候定址的動作就多了,效率就降低了。
- 為了減少定址,減少碎片檔案,合併是不得已的優化操作。
- Minor compact :可以用於把多個HFile檔案進行合併,同時可以刪除TTL過期的資料,但是手動刪除資料操作是不能被刪除的。為什麼這裡可以刪除TTL過期的資料?因為MemStore在LSM整理時,對於TTL過期只要不寫入HFile檔案就算是刪除了,而對於手動刪除資料操作則可能位於不同的HFile檔案中,因此做不到刪除。
- Major Compact:是把一個Store中的HFile檔案合併為一個HFile檔案,而不是把一個Region內的所有HFile檔案,因為一個Region可能有多個Column Family對應的Store。
2:Minor compact 策略百花爭鳴
2.1 RatioBasedCompactionPolicy合併策略
- (1) 對同一個Store的檔案,從舊到新逐一掃描所有候選檔案,滿足其中條件之一便停止掃描:
-
(2) 當前檔案大小 < 比它更新的所有檔案大小總和 * ratio,其中ratio是一個可變的比例,在高峰期時ratio為1.2,非高峰期為5,也就是非高峰期允許compact更大的檔案。那什麼時候是高峰期,什麼時候是非高峰期呢?使用者可以配置引數hbase.offpeak.start.hour和hbase.offpeak.end.hour來設定高峰期
-
(3) 當前所剩候選檔案數 >= hbase.store.compaction.min(預設為3)
-
(4) 當前所剩候選檔案數 <= hbase.store.compaction.max(預設為5)
-
(5) 停止掃描後,待合併檔案就選擇出來了,即為當前掃描檔案+比它新的所有檔案進行合併。
上例中:發現序號為4的檔案: 21 < (11+11)*1.2=26.4,符合合併條件。
- 悖論: 雖然大部分情況都是Memstore快滿了的時候才刷寫,但是實際情況很複雜,會出現Memstore刷寫出來的HFile不一定每次都是一樣大。最簡單能想到的是:要關閉某一個Region了,Memstore就不得不刷寫。因此出現如下情況:
-
結論: RatioBasedCompactionPolicy太差勁
經常引起大面積的合併,比如上例中,因為3太小了,肯定滿足當前檔案大小 < 比它更新的所有檔案大小總和 * ratio,發生大面積合併。注意合併的時候就不能寫入資料,經常合併就會引起IO,所以HBase在0.96版本之後就修改了合併演算法。
2.2 ExploringCompaction預設演算法(0.96版本後)
- 不再武斷的認為某個檔案滿足【當前檔案大小 < 比它更新的所有檔案大小總和 * ratio】,就把當前所有檔案+比它新的所有檔案都合併了,很極端。
- 根據【該檔案<(所有檔案大小-該檔案大小)*比例因子】公式,該公式不再強調順序性,而是把所有的檔案都遍歷一遍,若滿足公式就把該檔案放進待合併佇列組合中。
- 根據hbase.store.compaction.min和hbase.store.compaction.max兩個引數選挑選出多個檔案組合。 舉例如下:
- 在得到多個組合後,組合裡面選擇檔案數最多,檔案數一樣多時進一步選擇檔案總size最小的,目的在於儘可能多地合併檔案並且因compact帶來的IO壓力越小越好;
當前引數設定如下:
hbase.store.compaction.ratio=1.2 預設值
hbase.store.compaction.min=3 預設值
hbase.store.compaction.max=4 預設值為5
minCompactSize = 10
複製程式碼
那麼根據需要開始選擇多個組合:
-
如序列1: 根據計算公式:99>((3+12+33+10+11)*1.2),直接排除掉99,因為檔案太大了。
-
其他的檔案均滿足公式【該檔案<(所有檔案大小-該檔案大小)*比例因子】。因此會有如下組合:
a: 2 3 4 b: 2 3 4 5 c: 3 4 5 d: 3 4 5 6 e: 4 5 6 複製程式碼
-
最終選擇檔案數最多的,同時在b和d中選擇檔案大小最小的,其中b是58,d是66。因此最終會把b給合併了。
-
Ratio策略是0.94版本的預設策略,而0.96版本之後預設策略就換為了Exploring策略,在cloudera博文《what-are-hbase-compactions》中,作者給出了一個兩者的簡單效能對比,基本可以看出後者在節省IO方面會有10%左右的提升:
2.3 FIFOCompationPolicy策略(刪除策略)
適用場景:
- 場景在TTL特別短,比如儲存一些業務中間表,Mapreduce計算過程中暫時存取資料,用完這些資料就沒有用了,該場景下很容易出現整個塊的每一個單元格都過期了,
- BlockCache夠大,可以把整個RegionServer上儲存的資料都放進去,因此沒有必要合併任何檔案,因為基本可以走快取即可。
- 因為MemStore在LSM整理時,對於TTL過期只要不寫入HFile檔案就算是刪除了,所以FIFOCompationPolicy策略在合併時直接刪除所有單元格都過期的塊(不落盤而已),可以看到過期的塊被整個刪除掉了,沒有過期的塊完全沒有操作。整體上只有刪除沒有複製和移動,優點就是對CPU/IO幾乎沒有壓力。
不適用場景:
- 表沒有設定TTL,或者TTL=FOREVER
- 表設定了MIN_VERSIONs,並且MIN_VERSIONs>0
悖論:
- 手工是可以刪除MIN_VERSIONs的,會寫上墓碑標記,Major Compaction會刪除掉帶有墓碑標記的。
2.4 DateTieredCompactionPolicy策略(朋友圈原理)
- 新的1.3版本HBase增加了基於時間戳的分層compact策略,該方法借鑑自Cassandra。
- 基本思想就是將資料按時間戳分割槽,使得新老資料在不同的分割槽,compact行為在不同的分割槽內發生,這樣相當於把compact也按時間戳進行了拆分,好處之一就是提高了按時間讀取資料時候的效率,因為從指定的時間分割槽就可以獲取資料,而不再需要遍歷所有的檔案進行查詢。
- 防止舊檔案和新檔案合併在一起,因為新檔案往往是熱點資料。
- 這裡的時間窗不同傳統意義上隨時間向前滑動的時間窗,而是定期產生的新的時間窗,當前時刻的資料總是寫入最新形成的時間窗內。
朋友圈場景,Hbase應該具備什麼條件:
- 為了讀取效能,HFile檔案必須合併,但是合併的時候必須把新舊檔案分開處理,新的和新的合併,舊的和舊的合併。
- 太早的檔案就不再合併了,因為沒有人讀取,合併舊浪費了磁碟的效能。
DateTieredCompactionPolicy策略引數設定:
- hbase.hstore.compaction.date.tired.base.window.millis:基本的時間視窗,預設是6個小時,也就是說:從現在到6小時之內的HFile都在同一個時間視窗裡面,即這些檔案都在最新的時間視窗裡面。
- hbase.hstore.compaction.date.tired.windows.per.tier:層次增長倍數,分層的時候越老的時間視窗越寬。若基本時間視窗為1,則邊界一次是3,5,7,15,依次類推。
- hbase.hstore.compaction.min:在同一個視窗裡面檔案如果達到最小合併數,檔案就會合並,合併策略也是使用ExploringCompaction Policy,所謂策略套策略,太有才了!
- hbase.hstore.compaction.date.tired.max.tier.age.millis:最老的層次時間。當檔案太老了,老到超過所定義的時間範圍(以天為單位)就直接不合並了。但是也會存在問題:在這個最老的HFile檔案沒有TTL過期,當使用者手動刪除該檔案時,因為不會發生Major Compaction,所以這個資料根本就不會真正的刪除,而是一直佔著磁碟空間。
- 案例中發現:超過3小於7時,檔案合併了。
適用場景:
- 經常專注於讀寫最近資料的系統,或者說這個系統專注於最新的資料。
- 因為該策略有可能引發不了Major Compaction,沒有Major Compaction是沒有辦法刪除掉使用者手動刪除的資訊,所以更適用於那些基本不刪除資料的系統。
- 資料根據時間排序儲存。
- 資料只修改最近的資料,基本不刪除資料。
不適用場景:
- 資料改動非常頻繁,就連最老的資料也會頻繁改動。
- 經常邊讀邊寫資料。
2.5 StripeCompactionPolicy策略(檔案分層合併,穩定第一)
-
分層compact中將所有的檔案分成多個層,最頂層的叫L0,其下分別是L1、L2依此類推,同一層內各個資料檔案覆蓋的rowkey區間不會重疊,相鄰層之間的資料檔案可以進行compaction,由於區間不重疊每個key處於哪個資料檔案是確定的,因此compact過程中,只需部分檔案參與即可,而不需要所有檔案參與,有助於提高compaction執行效率。新寫入的資料會首先落到L0層,從L0層向下依次執行合併。
-
stripe compaction方案借鑑了上述方法,但是隻有兩層,level 0和level 1,隨著資料的寫入,memstore flush形成的hfile會首先落到level 0層,一旦level 0層的檔案數量超過了使用者的設定值,則將這些檔案寫入到level 1層,level 1層的資料按照rowkey覆蓋的範圍劃分成多個互不重疊的區間,每個區間稱為stripe,level 0的資料寫入時會首先讀出hfile的KVs,然後根據key定位到具體的stripe並將資料插入。
-
由於level的存在,get資料時會從依據block cache、memstore、level 0和level 1下hfile檔案的順序依次尋找,而compact會細化為level 0中的資料上升到level 1的過程以及level 1層內部資料檔案的合併,具體的compact策略複用了前面的exploring方法。每一個stripe相當於劃分出的subregion,這樣的設計使得compact的粒度變細(從region細化到sub-region級別),冷熱資料的compact相隔離,避免了compact時一次掃描整個region下所有的hfile檔案進行合併,提高了執行合併的效率,同時減少因compact帶來的阻塞時間。
-
a-f 屬於一個Strip,g-m 屬於一個Strip,以此類推。
StripeCompactionPolicy策略可以解決的問題:
- 讀取鏈路變長,效能會有損耗,但是提高了查詢速度的穩定性。
- 本來要牽涉全部HFile才能執行Major Compaction,現在可以分Strip執行了,比如:a-f這個strip就可以獨立執行Major Compaction 而不牽涉g-m。注意:執行Major Compaction才會真正刪除墓碑標記資料,否則資料是刪不掉的,這也是我們求賢若渴的原因所在。
- Major Comapction 一直以來都有牽涉的HFile檔案過多造成的IO不穩定的缺點。在StripeCompactionPolicy策略中,一次Major Comapction只會牽涉一個Strip中的所有檔案,所以克服了IO不穩定的缺點。
效能測試:
- 在不同的stripe數量以及不同的L0數量下的讀寫延遲對比情況,參考對照組可以看出,基本上任何配置下的讀響應延遲都有所降低,而寫響應延遲卻有所升高。
- 其中兩條藍線分別表示預設情況下的讀寫延遲曲線,而兩條紅線表示strips情況下讀寫延遲曲線,可以明顯看出來,無論讀還是寫,12-stripes配置下的穩定性都明顯好於預設配置,不會出現明顯的卡頓現象。
場景分析:
stripe compaction也有它特別擅長的業務場景,也有它並不擅長的業務場景。下面是兩種stripe compaction比較擅長的業務場景:
- 大Region。小region沒有必要切分為stripes,一旦切分,反而會帶來額外的管理開銷。一般預設如果region大小小於2G,就不適合使用stripe compaction。
- RowKey具有統一格式,stripe compaction要求所有資料按照Key進行切分,切分為多個stripe。如果rowkey不具有統一格式的話,無法進行切分,比如:用26個英文字母打頭來命名rowkey,就可以保證資料均勻分佈。如果使用timestamp來做rowkey,那麼資料就沒有辦法均勻分佈了,肯定不適合這個策略。
3 總結(黑貓白貓,抓住老鼠就是好貓)
Compaction對於HBase的讀寫效能至關重要,掌握好新舊技術的交替,才能讓Hbase成為一把利劍。辛苦成文,各自珍惜,謝謝!版權宣告:禁止轉載,歡迎學習