2/2)HBase GC的前生今世 – 演进篇

HBase GC的前生今世 – 演进篇 – 有态度的HBase/Spark/BigData http://hbasefly.com/2016/05/29/hbase-gc-2/

最原始的HBase CMS GC相当严重,经常会因为碎片过多导致Promotion Failure,严重影响业务的读写请求。幸运的是,HBase并没有止步不前,很多优化方案相继被提出并贡献给社区,本文要介绍的就是几个比较重要的核心优化,分别是针对Memstore所作的两个优化:Thread-Local Allocation Buffer和MemStore Chunk Pool 以及针对BlockCache所作的优化:BucketCache方案。在详细介绍这几个优化之前有必要简单介绍一下HBase GC优化的目标,很直观的,第一是要尽量避免长时间的Full GC,避免影响用户的读写请求;第二是尽量减少GC时间,提高读写性能;接着分别来看HBase针对GC所做的各种优化:

MemStore GC优化一 - Thread-Local Allocation Buffer
HBase数据写入操作实际上并没有直接将数据写入磁盘,而是先写入内存并顺序写入HLog,之后等待满足某个特定条件后统一将内存中的数据刷新到磁盘。一个RegionServer通常由多个Region组成,每张Region通常包含一张表的多个列族,而每个列族对应一块内存区域,这块内存被称为MemStore,很显然,一个RegionServer会由多个Region构成,一个Region会由多个MemStore构成。
最原始的HBase版本存在很严重的内存碎片,经常会导致长时间的Full GC,其中最核心的问题就出在MemStore这里。因为一个RegionServer由多个Region构成,不同Region的数据写入到对应Memstore,在JVM看来其实是混合在一起写入Heap的,此时假如Region1上对应的所有MemStore执行落盘操作,就会出现下图所示场景:

l1

为了优化这种内存碎片可能导致的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 统计了老生代的Max Chunk Size分别随时间的变化曲线,如下图所示:


l2

l3

由上图可以看出,未优化前碎片会大量出现导致频繁的Full GC,优化后虽然依然会产生大量碎片,但是最大碎片大小一直会维持在1e+08左右,极大地降低了Full GC频率。

MemStore GC优化二 – MemStore Chunk Pool
然而一旦一个Chunk写满之后,系统就会重新申请一个新的Chunk,这些Chunk大部分都会经过多次YGC之后晋升到老生代,如果某个Chunk再没有被引用就会被JVM垃圾回收。很显然,不断申请新的Chunk会导致YGC频率不断增多,YGC频率增加必然会导致晋升到老生代的Chunk增多,进而增加CMS GC发生的频率。如果这些Chunk能够被循环利用,系统就不需要申请新的Chunk,这样就会使得YGC频率降低,晋升到老生代的Chunk就会减少,CMS GC发生的频率就会降低。这就是MemStore Chunk Pool的核心思想,具体实现如下:

  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.94JVM参数:-Xms4G -Xmx4G -Xmn2G单条数据大小:Row size=50 bytes, Value size=1024 bytes实验方法:50 concurrent theads per client, insert 10,000,000 rows

测试结果:

YGC
YGCT
FGC
FGCT
GCT

优化前
747
36.503
48
2.492
38.995

优化后
711
20.344
4
0.284
20.628

很显然,经过优化后YGC时间降低了40+%左右,FGC的次数以及时间更是大幅下降。

BlockCache优化-BucketCache方案
对于需要深入了解HBase针对BlockCache所做的GC优化的朋友,强烈建议首先阅读之前的3篇 BlockCache 系列博文:part1 , part2 和 part3。文中重点介绍了BlockCache的两种实现方案:LRUBlockCache和BucketCache。

其中LRUBlockCache是目前HBase的默认方案,这种方案会将内存区分为3个部分:single-access区、mutil-access区以及in-memory区,一个Block块从HDFS中加载出来之后首先放入single区,后续如果有多次请求访问到这块数据的话,就会将这块数据移到mutil-access区。随着Block数据从single-access区晋升到mutil-access区,基本就伴随着对应的内存对象从young区到old区 ,晋升到old区的Block被淘汰后会变为内存垃圾,最终由CMS回收掉,CMS回收之后必然会产生大量的内存碎片,碎片空间一直累计就会产生臭名昭著的Full GC。

为了减少频繁 CMS GC 产生的碎片问题,社区采纳了阿里开发者的新方案:BucketCache。这种方案还是采用“将小碎片整理为大碎片”的思路,由程序在初始化的时候就申请了很多大小为2M的Bucket,数据Block的Get/Cache动作只是对这片空间的访问/覆写,CMS碎片会自然大大降低。BucketCache有三种工作模式:heap、offheap以及file,其中heap模式表示将数据存储在JVM堆内存,offheap模式表示将数据Block存储到操作系统内存,file模式表示将数据Block存储到类似于SSD的外部高速缓存上;很显然,offheap模式和file模式根本没有将数据Block存在JVM堆内存,所以几乎不会出现Full GC,而heap模式即使数据存储在JVM堆内存,也会因为内存由程序独立管理大大降低内存碎片。

针对BlockCache的两种实现方案,分别简单地对内存碎片产生情况和GC情况进行了统计,结果如下:


l4

YGC
YGCT(s)
FGC
FGCT(s)
GCT(s)

LRUBlockCache
79
26.8
75
13
39.8

BucketCache
171
11
1
0.462
11.462

从结果可以看出,BucketCache大大减少了碎片的产生,而且YGC和FGC时间也极大地得到了改善。需要注意的是,此结论是在部分缓存未命中的情况下得出的,缓存全部命中的场景结果会有所不同。

总结
所有构建在JVM上的应用或多或少都会受到GC的影响,尤其对于大内存系统更是如此,HBase也不例外。针对GC问题,一方面我们期待JVM能够做出更多地改进和优化,另一方面,我们也可以从内存管理方面进行更多地探索,不断优化内存的使用。HBase在0.98之后的版本还不断针对GC进行着优化,后续再进行补充!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容