HBase 如何避免 Full GC ?

本文介绍如何通过选择合适的垃圾回收策略来优化HBase中的RegionServer性能,避免长时间的FullGC导致的服务中断问题。

前言

本文隶属于专栏《大数据技术体系》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢!

本专栏目录结构和参考文献请见大数据技术体系


正文

随着 JVM 堆内存的越大,Full GC 的时间变得很久,Full GC 有时候可以达到好几分钟。

在 Ful1 GC 的时候 JVM 会停止响应任何的请求,整个 JVM 的世界就像是停止了一样,所以这种暂停又被叫做 Stop-The-World(STW)。

关于 Full GC 请参考我的博客——Minor GC和Full GC有什么区别?

当 ZooKeeper 像往常一样通过心跳来检测 RegionServer 节点是否存活的时候,发现已经很久没有接收到来自 RegionServer 的回应,会直接把这个 RegionServer 标记为已经宕机。

等到这台 RegionServer 终于结束了 Full GC 后,去查看 ZooKeeper 的时候会发现原来自己己经“被宕机”了,为了防止脑裂问题的发生,它会自己停止自己。

这种场景称为 RegionServer 自杀,它还有另一个美丽的名字叫朱丽叶暂停,而且这问题还挺常见的,早期一直困扰着 HBase 开发人员。

所以我们一定要设定好 GC 回收策略,避免长时间的 Full GC 发生,或者是尽量减小 Full GC 的时间。


GC 回收策略优化

由于数据都是在 RegionServer 里面的,Master 只是做一些管理操作,所以一般内存问题都出在 RegionServer 上。接下来主要用 RegionServer 来讲解参数配置,如果你想调整 Master 的内存参数,只需要把 HBASE_REGIONSERVER_OPTS 换成 HBASE_MASTER _OPTS 就行了。

JVM 通常提供了 4 种 GC 回收器:

  1. 串行回收器(SerialGC)。
  2. 并行回收器(ParallelGC),主要针对年轻带进行优化(JDK8 默认策略)。
  3. 并发回收器(ConcMarkSweepGC,简称 CMS),主要针对年老带进行优化。
  4. G1 GC回收器,主要针对大内存(32GB以上才叫大内存)进行优化。

详情请见我的博客——JVM中有哪些垃圾收集器?

接下来我们来说说具体的组合方案。


ParallelGC 和 CMS 的组合方案

并行收回器的性能虽然没有串行回收器那么好,但是 FullGC 时间较短。

对于 RegionServer 来说,Full GC 是致命的,就算性能下降一些也没有关系,所以我们最好使用并行回收器。

并发回收器主要是减少老年代的暂停时间,可以保证应用不停止的情况下进行收集。

但是它也有缺点,那就是每次都会留下一些“浮动垃圾”。

这些浮动垃圾只能在下次垃圾回收的时候被回收,不过这些我们也可以忍受。

基于以上描述比较符合HBase的配置是:

  • 年轻代使用并行回收器ParallelGC。
  • 年老代使用并发回收器 CMS。

修改的方式还是修改 $HBASE_HOME/conf/hbase-env.sh,在我们修改 xmsxmx 的地方加上 -XX:+UseParNewGC-XX:+UseConcMarkSweepGC

就像这样:

export HBASE REGIONSERVER OPTS-"SHBASE REGIONSERVER_OPTS -Xmx8g -Xms8g -XX:+UseParNewGC -XX:+UseConcMarkSweepGC"

G1GC 方案

关于 G1GC 请参考我的博客——G1 GC是什么?

如果你的 JDK 版本大于 1.7.004(JDK7 update4),并且你的 RegionServer 内存大于 4GB(换句话说如果小于 4GB 就不用考虑 G1GC 了, 直接用 ParallellGC+CMS),你可以考虑使用 G1GC 策略,这是 JDK7 新加入的策略。

不过仅仅是考虑,请不要不进行测试比较就直接改为 G1GC。

这种策略专门适用于堆内存很大的情况。

引入 G1GC 策略的原因是, 就算采用了 CMS 策略,我们还是不能避免 FullGC。

因为在以下两种情况下,CMS 还是会触发 Full GC:

在 CMS 工作的时候,有一些对象要从年轻代移动到老年代,但是此时老年代空间不足了,此时只能触发 Full GC,然后引发 STW(Stop The World)暂停,JVM 又开始不响应任何请求了。

当被回收掉的内存空间太碎太细小,导致新加入老年代的对象放不进去,只好触发 Full GC 来整理空间,JVM 还是会进入不响应任何请求的状态。

G1GC 策略通过把堆内存划分为多个 Region,然后对各个 Region 单独进行 GC,这样整体的 Full GC 可以被最大限度地避免(FullGC还是不可避免的,我们只是尽力延迟 FullGC 的到来时间),而且这种策略还可以通过手动指定 MaxGCPauseMillis 参数来控制一旦发生 Full GC 的时候的最大暂停时间,避免时间太长造成 RegionServer 自杀。

设置的方式是:

export HBASE_REGIONSERVER_OPTS="$HBASE_REGIONSERVER _OPTS=-Xmx24g -Xms24g -XX:+UseG1GC -XX:MaxGCPauseMillis=100"

这里说的堆内存很大的情况,具体指的是多大大概是 32GB 、 64GB 或者以上,这样才算大内存。

如果你的 RegionServer 占用的内存大概在 4GB~32GB ,需要通过亲自试验才知道哪种策略适合你。

没有哪种策略是最好的,如果有的话 JVM 早就把别的策略都删除了,所以究竟是使用并行回收器和并发回收器的组合,还是使用 G1GC ,这还得靠大家通过具体试验来判断。

不过还是有一些简单的方式可以决定使用哪种策略:

  • 如果你的 RegionServer 内存小于 4GB ,就不需要考虑 G1GC 策略了,直接用 -XX:+UseParNewGC -XX+UseConcMarkSweepGC
  • 如果你的 RegionServer 内存大于 32GB ,建议使用 G1GC 策略。

试验的时候或者运行的时候都要记得把调试参数加上: -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintAdaptiveSizePolicy

这样才能看到试验的量化结果,为试验提供更详细的信息。


在此引用 Justin Kestelyn 在文章 Tuning Java Garbage Collection for HBase 中经过测试得出的调优参数结果,供大家参考。

  • 32GB heap 的时候,-XX:G1NewSizePercent=3 。
  • 64GB heap 的时候,-XX:G1NewSizePercent=2 。
  • 100GB 或者更大的内存的时候,-XX:G1NewSizePercent=1 。

其他参数:

  • -XX:+UseG1GC 。
  • -Xms100g -Xmx100g (文中做实验的堆内存大小)。
  • -XX:MaxGCPauseMillis=100 。
  • -XX:+ParallelRefProcEnabled 。
  • -XX:-ResizePLAB 。
  • -XX:ParallelGCThreads= 8+(40-8)(5/8)=28 (40 为本地 CPU 核心数)
  • -XX:G1NewSizePercent=1 。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值