问题描述
在测试Phoenix稳定性时,发现HBase集群其中一台RegionServer节点FullGC严重,隔一段时间就会挂掉。
HBase集群规格
初步分析
使用jstat监控RegionServer的Heap Size和垃圾回收情况
Old区内存一直在90%多,且FullGC次数一直在增多。
通过ganglia查看集群的FullGC情况,也可以看出003节点持续在FullGC,并最终挂掉。
怀疑存在内存泄漏导致FullGC可回收的内存越来越小,回收的时间也越来越长,最终导致RegionServer心跳超时,被Master干掉。
问题定位
排查内存泄漏问题,可借助jmap分析java堆内存的占用情况,jmap使用参考:https://blog.csdn.net/xidiancoder/article/details/70948569
使用jmap将RegionServer堆内存dump下来:
可以看到Configuration对象已经占用到80%堆内存,Configuration底层使用HashTable存配置的键值对,与上图内存分配相符,但是还不确定这么多对象是哪里来的以及为什么没有被回收。
查看内存泄漏详细信息:
在堆内存Histogram中,过滤到Configuration对象,然后Merge Shortest path to GC Roots:
FSHLOG引用OpenRegionHandler$PostOpenDeployTasksThread线程对象,进一步引用HRegion,HRegion引用Coprocessor,然后引用Configuration对象,导致内存泄露。
结合FSHLog源码:
syncFuturesByHandler缓存写WAL的每个线程,但是在线程结束时并不会清除Map中缓存的线程,导致引用的Configuration对象不会被释放。
问题修复
目前该问题已有阿里云HBase社区commiter正研修复并贡献给社区:
https://issues.apache.org/jira/browse/HBASE-21228
纯 Java 源码分享公众号,目前有「Dubbo」「SpringCloud」「Java 并发」「RocketMQ」「Sharding-JDBC」「MyCAT」「Elastic-Job」「SkyWalking」「Spring」等等。