hbase針對fullgc所做的優化(Memstore所作的優化 針對BlockCache所作優化)

先看:
深入研究java gc https://blog.51cto.com/12445535/2372976
老年代 CMS gc回收算法 對hbase的影響 https://blog.51cto.com/12445535/2373206

1、最原始的HBase CMS GC相當嚴重,經常會因爲碎片過多導致Promotion Failure,嚴重影響業務的讀寫請求。
2、分別是針對Memstore所作的兩個優化:Thread-Local Allocation Buffer和MemStore Chunk Pool
3、以及針對BlockCache所作的優化:BucketCache方案。
4、在詳細介紹這幾個優化之前有必要簡單介紹一下HBase GC優化的目標,很直觀的,
5、第一是要儘量避免長時間的Full GC,避免影響用戶的讀寫請求;
6、第二是儘量減少GC時間,提高讀寫性能;
7、接着分別來看HBase針對GC所做的各種優化:

MemStore GC優化一 - Thread-Local Allocation Buffer
回顧hbase數據寫流程
1、HBase數據寫入操作實際上並沒有直接將數據寫入磁盤,
2、而是先寫入內存並順序寫入HLog,
3、之後等待滿足某個特定條件後統一將內存中的數據刷新到磁盤。
4、一個RegionServer通常由多個Region組成,每張Region通常包含一張表的多個列族,而每個列族對應一塊內存區域,這塊內存被稱爲MemStore,
5、很顯然,一個RegionServer會由多個Region構成,一個Region會由多個MemStore構成。

老版本hbase中:
1、最原始的HBase版本存在很嚴重的內存碎片,經常會導致長時間的Full GC,其中最核心的問題就出在MemStore這裏。
2、因爲一個RegionServer由多個Region構成,不同Region的數據寫入到對應Memstore,
3、在JVM看來其實是混合在一起寫入Heap(堆內存)的

爲了優化這種內存碎片可能導致的Full GC,HBase借鑑了Arena Allocation內存管理方式,它通過順序化分配內存、內存數據分塊等特性使得內存碎片更加粗粒度,有效改善Full GC情況;

具體實現原理如下:

  1. 每個MemStore會實例化出來一個MemStoreLAB
  2. MemStoreLAB會申請一個2M大小的Chunk數組和一個Chunk偏移量,初始值爲0
  3. 當一個KeyValue值插入MemStore後,MemStoreLAB會首先通過KeyValue.getBuffer()取得data數組,並將data數組複製到Chunk數組中,之後再將Chunk偏移量往前移動data.length
  4. 如果當前Chunk滿了之後,再調用new byte[ 2 1024 1024]申請一個新的Chunk

提示:
很顯然,通過申請2M大小的Chunk可以使得內存碎片更加粗粒度,官方在優化前後通過設置 -xx:PrintFLSStatistics = 1
未優化前碎片會大量出現導致頻繁的Full GC,優化後雖然依然會產生大量碎片,但是最大碎片大小一直會維持在1e+08左右,極大地降低了Full GC頻率。

MemStore GC優化二 – MemStore Chunk Pool
MemStore Chunk Pool的核心思想爲:
1、如果這些Chunk能夠被循環利用,系統就不需要申請新的Chunk,這樣就會使得YGC頻率降低,晉升到老生代的Chunk就會減少,CMS GC發生的頻率就會降低。

爲什麼Chunk不能被循環利用呢?
1、一旦一個Chunk寫滿之後,系統就會重新申請一個新的Chunk,
2、這些Chunk大部分都會經過多次YGC之後晉升到老生代,如果某個Chunk再沒有被引用就會被JVM垃圾回收。
3、很顯然,不斷申請新的Chunk會導致YGC頻率不斷增多,YGC頻率增加必然會導致晉升到老生代的Chunk增多,進而增加CMS GC發生的頻率。

具體實現如下:

  1. 系統會創建一個Chunk Pool來管理所有未被引用的chunks,這些chunk就不會再被JVM當作垃圾回收掉了
  2. 如果一個Chunk沒有再被引用,將其放入Chunk Pool
  3. 如果當前Chunk Pool已經達到了容量最大值,就不會再接納新的Chunk
  4. 如果需要申請新的Chunk來存儲KeyValue,首先從Chunk Pool中獲取,如果能夠獲取得到就重複利用,如果爲null就重新申請一個新的Chunk

官方針對該優化也進行了簡單的測試,使用jstat -gcutil對優化前後的JVM GC情況進行了統計,具體的測試條件和測試結果如下所示:

測試條件:
HBase版本:0.94
JVM參數:-Xms4G -Xmx4G -Xmn2G
單條數據大小:Row size=50 bytes, Value size=1024 bytes
實驗方法:50 concurrent theads per client, insert 10,000,000 rows
//cdh中參數爲:
根據 MSLAB 分配方式分配的塊區大小
hbase.hregion.memstore.mslab.chunksize = 2M
MemStoreChunkPool&MSLAB提升HBASE GC性能 https://blog.csdn.net/map_lixiupeng/article/details/40914567

BlockCache優化-BucketCache方案
1、BucketCache。這種方案還是採用“將小碎片整理爲大碎片”的思路,
2、由程序在初始化的時候就申請了很多大小爲2M的Bucket,數據Block的Get/Cache動作只是對這片空間的訪問/覆寫,CMS碎片會自然大大降低。

1、其中heap模式表示將數據存儲在JVM堆內存,
2、offheap模式表示將數據Block存儲到操作系統內存,
3、file模式表示將數據Block存儲到類似於SSD的外部高速緩存上;
//很顯然,offheap模式和file模式根本沒有將數據Block存在JVM堆內存,所以幾乎不會出現Full GC,而heap模式即使數據存儲在JVM堆內存,也會因爲內存由程序獨立管理大大降低內存碎片。
從結果可以看出,BucketCache大大減少了碎片的產生,而且YGC和FGC時間也極大地得到了改善。

參考鏈接:
http://hbasefly.com/2016/05/29/hbase-gc-2/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章