Yarn ResourceManager GC overhead limit exceeded
问题
FATAL yarn.YarnUncaughtExceptionHandler (YarnUncaughtExceptionHandler.java:uncaughtException(51)) - Thread Thread[Timer for 'ResourceManager' metrics system,5,main] threw an Error. Shutting down now...
java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.util.ArrayList.iterator(ArrayList.java:840)
at org.apache.hadoop.metrics2.source.JvmMetrics.getGcUsage(JvmMetrics.java:134)
at org.apache.hadoop.metrics2.source.JvmMetrics.getMetrics(JvmMetrics.java:103)
at org.apache.hadoop.metrics2.impl.MetricsSourceAdapter.getMetrics(MetricsSourceAdapter.java:199)
at org.apache.hadoop.metrics2.impl.MetricsSystemImpl.snapshotMetrics(MetricsSystemImpl.java:420)
at org.apache.hadoop.metrics2.impl.MetricsSystemImpl.sampleMetrics(MetricsSystemImpl.java:407)
at org.apache.hadoop.metrics2.impl.MetricsSystemImpl.onTimerEvent(MetricsSystemImpl.java:382)
at org.apache.hadoop.metrics2.impl.MetricsSystemImpl$4.run(MetricsSystemImpl.java:369)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
解决办法
最简单有效的修改ResourceManager Java heap size 增加即可
分析(网上一大堆但是解决方法都不行,这里copy一个分析不较好的)
1.最先想到的是由于内存泄漏导致,因此到集群上取Dump文件,最开始使用的是命令(jmap
-dump:live,format=b,file=dump.hprof 22439)获取dump文件的,但是导致的一个结果就是把ResourceManager搞挂了,后来才知道是因为探索环境的yarn使用的是G1垃圾回收机制,对于G1垃圾回收机制,使用上面的方式可能会将进程搞挂掉,改成下面的命方式即可成功的获取dump文件:jmap-J-d64 -dump:live,format=b,file=yarn-22439.dump 22439 。
2.通过对dump文件的内存泄漏检测分析,发现
在类AsyncDispatcher中的一个属性(BlockingQueue eventQueue)的对象占用了大量的内存,因此怀疑是该对象发生了内存泄漏。
- 通过类AsyncDispatcher的源码,发现其内部类GenericEventHandler会在处理消息的时候将上面怀疑是内存泄漏的对象eventQueue的size打印出来,因此决定查看线上yarn的日志,看此队列的长度
下图是列出的队列的长度,可明显可以看出该队列的尺寸达到了上千万,这肯定是有问题的。而正常的大集群的日志中队列的长度只有几千,很明显该对象是有问题的。
4.再通过内存分析工具发现,上述有异常的队列中存放的都是ContainerFinishedEvent和ContainerCreatedEvent对象,因此去查看该对象是在哪被创建和消费的。
-
通过对源码进行分析定位到ContainerFinishedEvent事件是在类SystemMetricsPublisher中被消费掉的,该类是将ContainerFinishedEvent封装成TimelineEntity实体之后通过Http的post方式发送给yarn的TimelineServer进程。
-
综上分析,目前的主要原因是由于消费者(也就是往TimelineServer发送Event事件数据)发送数据的能力不够,导致消息队列中缓存的大量的消息,随着时间的推移,消息数据不断增多,从而导致yarn内存不够用,从而需要重启。