hbase

HBase-GC性能优化

2018-10-29  本文已影响71人  蠟筆小噺没有烦恼

1 JVM调优

1.1 堆内存

默RegionServer的堆内存为1G,这里Memstore默认站40%,也就是400M,在实际场景中很容易因为Memstore太小导致阻塞,修改参数,在cong/hbase-env.sh:

export HBASE_HEAPSIZE=8G

该参数会将Master和RegionServer的堆内存都设置为8G,所以有需要的话尽量使用专用的堆内存设置项:

export HBASE_MASTER_OPTS="$HBASE_MASTER_OPTS -Xms4g -Xmx4G"
export HBASE_REGIONsERVER_OPTS="$HBASE_REGIONSERVER_OPTS -Xms8g -Xmx8G"

就可以将Master调整为4G,RegionServer调整为8G。需要注意的是,不管在什么时候都必须保证物理机留有10%的内存给操作系统做必要的操作。一般来说,如果物理机上还有计算框架,那么RegionServer的内存占有率应该是计算框架之外最大的。
还需要注意的是,如果JDK版本低于8,HBase会有一个内存泄漏的Bug,永久对象区(Permanent Generation,这个区域在非堆内存里边)必须这只如下项:

export HBASE_MASTER_OPTS="$HBASE_MASTER_OPTS -xx:PermSize=128m -XX:MaxPermSize=128m"
export HBASE_REGIONsERVER_OPTS="$HBASE_REGIONSERVER_OPTS -xx:PermSize=128m -XX:MaxPermSize=128m"

如果Xmx调的比较大了,那么需要把PermSize和maxPermSize调整的都大一些(一般不会出现这种情况,128M已经够大了)。JDK8+就不需要这个操作了。

1.2 Full GC的影响

一般来说RegionServer的堆内存越大越好,但是因为垃圾回收的缘故,内存大了之后,相应的FullGC时间也会线性增加,一般来说每G的内存需要的FullGC时间为:。FullGC优势可能达到好几分钟,这个阶段会停止响应任何请求,相当于所有线程挂起,这种暂停又叫做Stop-The-World(STW),FullGc的对HBase造成严重后果比较严重:
在Zookeeper检测RegionServer心跳包的时候,RegionServer正在FullGc无法回应,而如果超过阀值等待时间会被标记为宕机,这时候会将该RegionServer上的数据向其他RegionServer迁移,并且该RegionServerFullGc结束后发现自己被宕机了,为了防止脑裂,会停止自己(RegionServer自杀,又叫朱丽叶暂停)。很多场景下会将zookeeper的心跳检测阀值调大,但是这并不可取。
GC回收策略优化
为了避免长时间FullGC或者减少FullGc的发生,JVM提供了四中GC回收器:

1.2.1 ParallelGC和CMS组合方案

并行回收器的性能没有串行回收器好但是FullGC时间较短;而并发回收器主要可以减少老年代的暂停时间,并且可以保证不停止的情况下进行收集,但是每次回留下一些“浮动垃圾”,只能在下次回收的时候被回收。所以Hbase比较符合的配置是:

依旧在conf/hbase-env.sh,如果需要修改Master的,将RegionServer修改为Master即可:

export HBASE_REGIONsERVER_OPTS="$HBASE_REGIONSERVER_OPTS -Xmx8g -Xms8g -XX:+UseParNewGC -XX:+UseConcMarkSweepGC"

1.2.2 G1GC回收方案

G1GC是在JDK1.7.0_O4(jdk7 update4)中新增的,并且如果RegionServer内存很大,大于4G的话就可以考虑G1GC。之所以引入了G1GC,是因为CMS回收依旧不能避免FullGC,发生在如下两种情况:

1.3 Memstore的专属JVM策略MSLAB

堆内存非常大的时候,FullGC时间非常长,此时解决FullGC问题不能完全依靠JVM自身的垃圾回收器,MSLAB是为MemStore专门设计的内存管理策略,对标CMS。采用CMS发生FullGC的原因主要有;

之所以会出现碎片内存空间,是因为MemStore定期刷写为一个HFile,刷新完成后Memstore所占用的空间就会被回收, 但是因为内存分配都是顺序分配的,导致逐渐出现Memstore位置为碎片空间,产生不连续内存。直到没有任何一块连续内存不能存放新的数据,JVM只好进行STW,使用单进程进行内存空间重新排列。

1.3.1 LTAB方案

不过JVM为了解决碎片内存问题,有一个TLAB(Thread-Local allocation buffer)方案,每个线程都会分配一个固定大小的内存空间,专门给这个线程使用,用完之后释放,新线程也会申请这么大的空间,就不会出现碎片空间。明显的缺点是,如果线程中的对象不需要占用整个线程申请的对象会导致很大的内存浪费闲置,内存空间利用率降低,但是为了避免FullGC还是可以考虑的。
但是HBase不能直接使用该方案,因为HBase的多个Region是被一个线程管理的,多个Memstore占用的空间不能合理分开,于是HBase基于TLAB实现了MSLAB。

1.3.2 MSLAB-Memstore-Local Allocation BUffers

MSLAB完全按照TLAB实现思路,只不过内存是由Memstore来分配的,实现思路为:

堆内存按照chunk为单位划分为规则空间,消除了碎片空间导致的无法插入数据的问题,但是有时候只写入1kB数据也需要2M的chunk空间,但是可以容忍。相关参数如下,在hbase-site.xml中配置:

#设置为true,打开MSLAB,默认为true
hbase.hregion.memstore.mslab.enabled
#每个chunk大小,默认2MB,2048*1024B
hbase.hregion.memstore.mslab.chunksize
#能放入chunk的最大单元格大小,默认为256K
hbase.hregion.memstore.mslab.max.allocation
#在整个memstore可以占用的堆内存中,chunkPool占用的比例,默认为0.0,最大1.0
hbase.hregion.memstore.chunkpool.maxsize
#在RegionServer启动的时候可以预分配一些空的chunk出来放到chunkPool中待使用,改制代表了预分配的chunk占总的chunkPool比例,默认为0.0,最大1.0
hbase.hregion.memstore.chunkpool.initialsize

MSLAB使用注意事项
MSLAB可以和G1GC一起使用,没有冲突。不过看起来MSLAB和G1的实现思路很接近,其实G1是后来才出现的策略,并且根据测试,结合使用的性能会更高。

上一篇 下一篇

猜你喜欢

热点阅读