天天看點

HBase性能調優

因官方BookPerformanceTuning部分章節沒有按配置項進行索引,不能達到快速查閱的效果。是以我以配置項驅動,重新整理了原文,并補充一些自己的了解,如有錯誤,歡迎指正。

配置優化

zookeeper.session.timeout

預設值:3分鐘(180000ms)

說明:RegionServer與Zookeeper間的連接配接逾時時間。當逾時時間到後,ReigonServer會被Zookeeper從RS叢集清單中移除,HMaster收到移除通知後,會對這台server負責的regions重新balance,讓其他存活的RegionServer接管.

調優:

這個timeout決定了RegionServer是否能夠及時的failover。設定成1分鐘或更低,可以減少因等待逾時而被延長的failover時間。

不過需要注意的是,對于一些Online應用,RegionServer從當機到恢複時間本身就很短的(網絡閃斷,crash等故障,運維可快速介入),如果調低timeout時間,反而會得不償失。因為當ReigonServer被正式從RS叢集中移除時,HMaster就開始做balance了(讓其他RS根據故障機器記錄的WAL日志進行恢複)。當故障的RS在人工介入恢複後,這個balance動作是毫無意義的,反而會使負載不均勻,給RS帶來更多負擔。特别是那些固定配置設定regions的場景。

hbase.regionserver.handler.count

預設值:10

說明:RegionServer的請求處理IO線程數。

這個參數的調優與記憶體息息相關。

較少的IO線程,适用于處理單次請求記憶體消耗較高的BigPUT場景(大容量單次PUT或設定了較大cache的scan,均屬于BigPUT)或ReigonServer的記憶體比較緊張的場景。

較多的IO線程,适用于單次請求記憶體消耗低,TPS要求非常高的場景。設定該值的時候,以監控記憶體為主要參考。

這裡需要注意的是如果server的region數量很少,大量的請求都落在一個region上,因快速充滿memstore觸發flush導緻的讀寫鎖會影響全局TPS,不是IO線程數越高越好。

壓測時,開啟EnablingRPC-levellogging,可以同時監控每次請求的記憶體消耗和GC的狀況,最後通過多次壓測結果來合理調節IO線程數。

這裡是一個案例HadoopandHBaseOptimizationforReadIntensiveSearchApplications,作者在SSD的機器上設定IO線程數為100,僅供參考。

hbase.hregion.max.filesize

預設值:256M

說明:在目前ReigonServer上單個Reigon的最大存儲空間,單個Region超過該值時,這個Region會被自動split成更小的region。

小region對split和compaction友好,因為拆分region或compact小region裡的storefile速度很快,記憶體占用低。缺點是split和compaction會很頻繁。

特别是數量較多的小region不停地split,compaction,會導緻叢集響應時間波動很大,region數量太多不僅給管理上帶來麻煩,甚至會引發一些Hbase的bug。

一般512以下的都算小region。

大region,則不太适合經常split和compaction,因為做一次compact和split會産生較長時間的停頓,對應用的讀寫性能沖擊非常大。此外,大region意味着較大的storefile,compaction時對記憶體也是一個挑戰。

當然,大region也有其用武之地。如果你的應用場景中,某個時間點的通路量較低,那麼在此時做compact和split,既能順利完成split和compaction,又能保證絕大多數時間平穩的讀寫性能。

既然split和compaction如此影響性能,有沒有辦法去掉?

compaction是無法避免的,split倒是可以從自動調整為手動。

隻要通過将這個參數值調大到某個很難達到的值,比如100G,就可以間接禁用自動split(RegionServer不會對未到達100G的region做split)。

再配合RegionSplitter這個工具,在需要split時,手動split。

手動split在靈活性和穩定性上比起自動split要高很多,相反,管理成本增加不多,比較推薦online實時系統使用。

記憶體方面,小region在設定memstore的大小值上比較靈活,大region則過大過小都不行,過大會導緻flush時app的IOwait增高,過小則因storefile過多影響讀性能。

hbase.regionserver.global.memstore.upperLimit/lowerLimit

預設值:0.4/0.35

upperlimit說明:hbase.hregion.memstore.flush.size這個參數的作用是當單個Region内所有的memstore大小總和超過指定值時,flush該region的所有memstore。RegionServer的flush是通過将請求添加一個隊列,模拟生産消費模式來異步處理的。那這裡就有一個問題,當隊列來不及消費,産生大量積壓請求時,可能會導緻記憶體陡增,最壞的情況是觸發OOM。

這個參數的作用是防止記憶體占用過大,當ReigonServer内所有region的memstores所占用記憶體總和達到heap的40%時,HBase會強制block所有的更新并flush這些region以釋放所有memstore占用的記憶體。

lowerLimit說明:同upperLimit,隻不過lowerLimit在所有region的memstores所占用記憶體達到Heap的35%時,不flush所有的memstore。它會找一個memstore記憶體占用最大的region,做個别flush,此時寫更新還是會被block。lowerLimit算是一個在所有region強制flush導緻性能降低前的補救措施。在日志中,表現為“**Flushthreadwokeupwithmemoryabovelowwater.”

調優:這是一個Heap記憶體保護參數,預設值已經能适用大多數場景。

參數調整會影響讀寫,如果寫的壓力大導緻經常超過這個閥值,則調小讀緩存hfile.block.cache.size增大該閥值,或者Heap餘量較多時,不修改讀緩存大小。

如果在高壓情況下,也沒超過這個閥值,那麼建議你适當調小這個閥值再做壓測,確定觸發次數不要太多,然後還有較多Heap餘量的時候,調大hfile.block.cache.size提高讀性能。

還有一種可能性是hbase.hregion.memstore.flush.size保持不變,但RS維護了過多的region,要知道region數量直接影響占用記憶體的大小。

hfile.block.cache.size

預設值:0.2

說明:storefile的讀緩存占用Heap的大小百分比,0.2表示20%。該值直接影響資料讀的性能。

調優:當然是越大越好,如果寫比讀少很多,開到0.4-0.5也沒問題。如果讀寫較均衡,0.3左右。如果寫比讀多,果斷預設吧。設定這個值的時候,你同時要參考hbase.regionserver.global.memstore.upperLimit,該值是memstore占heap的最大百分比,兩個參數一個影響讀,一個影響寫。如果兩值加起來超過80-90%,會有OOM的風險,謹慎設定。

hbase.hstore.blockingStoreFiles

預設值:7

說明:在flush時,當一個region中的Store(CoulmnFamily)内有超過7個storefile時,則block所有的寫請求進行compaction,以減少storefile數量。

調優:block寫請求會嚴重影響目前regionServer的響應時間,但過多的storefile也會影響讀性能。從實際應用來看,為了擷取較平滑的響應時間,可将值設為無限大。如果能容忍響應時間出現較大的波峰波谷,那麼預設或根據自身場景調整即可。

hbase.hregion.memstore.block.multiplier

預設值:2

說明:當一個region裡的memstore占用記憶體大小超過hbase.hregion.memstore.flush.size兩倍的大小時,block該region的所有請求,進行flush,釋放記憶體。

雖然我們設定了region所占用的memstores總記憶體大小,比如64M,但想象一下,在最後63.9M的時候,我Put了一個200M的資料,此時memstore的大小會瞬間暴漲到超過預期的hbase.hregion.memstore.flush.size的幾倍。這個參數的作用是當memstore的大小增至超過hbase.hregion.memstore.flush.size2倍時,block所有請求,遏制風險進一步擴大。

調優:這個參數的預設值還是比較靠譜的。如果你預估你的正常應用場景(不包括異常)不會出現突發寫或寫的量可控,那麼保持預設值即可。如果正常情況下,你的寫請求量就會經常暴長到正常的幾倍,那麼你應該調大這個倍數并調整其他參數值,比如hfile.block.cache.size和hbase.regionserver.global.memstore.upperLimit/lowerLimit,以預留更多記憶體,防止HBaseserverOOM。

hbase.hregion.memstore.mslab.enabled

預設值:true

說明:減少因記憶體碎片導緻的FullGC,提高整體性能。

調優:詳見http://kenwublog.com/avoid-full-gc-in-hbase-using-arena-allocation

其他

啟用LZO壓縮

LZO對比Hbase預設的GZip,前者性能較高,後者壓縮比較高,具體參見UsingLZOCompression。對于想提高HBase讀寫性能的開發者,采用LZO是比較好的選擇。對于非常在乎存儲空間的開發者,則建議保持預設。

不要在一張表裡定義太多的ColumnFamily

Hbase目前不能良好的處理超過包含2-3個CF的表。因為某個CF在flush發生時,它鄰近的CF也會因關聯效應被觸發flush,最終導緻系統産生更多IO。

批量導入

在批量導入資料到Hbase前,你可以通過預先建立regions,來平衡資料的負載。詳見TableCreation:Pre-CreatingRegions

避免CMSconcurrentmodefailure

HBase使用CMSGC。預設觸發GC的時機是當年老代記憶體達到90%的時候,這個百分比由-XX:CMSInitiatingOccupancyFraction=N這個參數來設定。concurrentmodefailed發生在這樣一個場景:

當年老代記憶體達到90%的時候,CMS開始進行并發垃圾收集,于此同時,新生代還在迅速不斷地晉升對象到年老代。當年老代CMS還未完成并發标記時,年老代滿了,悲劇就發生了。CMS因為沒記憶體可用不得不暫停mark,并觸發一次stoptheworld(挂起所有jvm線程),然後采用單線程拷貝方式清理所有垃圾對象。這個過程會非常漫長。為了避免出現concurrentmodefailed,建議讓GC在未到90%時,就觸發。

通過設定-XX:CMSInitiatingOccupancyFraction=N

這個百分比,可以簡單的這麼計算。如果你的hfile.block.cache.size和hbase.regionserver.global.memstore.upperLimit加起來有60%(預設),那麼你可以設定70-80,一般高10%左右差不多。

Hbase用戶端優化

AutoFlush

将HTable的setAutoFlush設為false,可以支援用戶端批量更新。即當Put填滿用戶端flush緩存時,才發送到服務端。

預設是true。

ScanCaching

scanner一次緩存多少資料來scan(從服務端一次抓多少資料回來scan)。

預設值是1,一次隻取一條。

ScanAttributeSelection

scan時建議指定需要的ColumnFamily,減少通信量,否則scan操作預設會傳回整個row的所有資料(所有CoulmnFamily)。

CloseResultScanners

通過scan取完資料後,記得要關閉ResultScanner,否則RegionServer可能會出現問題(對應的Server資源無法釋放)。

OptimalLoadingofRowKeys

當你scan一張表的時候,傳回結果隻需要rowkey(不需要CF,qualifier,values,timestaps)時,你可以在scan執行個體中添加一個filterList,并設定MUST_PASS_ALL操作,filterList中addFirstKeyOnlyFilter或KeyOnlyFilter。這樣可以減少網絡通信量。

TurnoffWALonPuts

當Put某些非重要資料時,你可以設定writeToWAL(false),來進一步提高寫性能。writeToWAL(false)會在Put時放棄寫WALlog。風險是,當RegionServer當機時,可能你剛才Put的那些資料會丢失,且無法恢複。

啟用BloomFilter

BloomFilter通過空間換時間,提高讀操作性能。

繼續閱讀