问题描述
最近公司的线上监控系统给我推送了一些kafka lag持续增加的消息,我上生产环境去看了相应的consumer的状况,发现几台机器虽然还在处理消息,可是速度明显慢了不少。node
问题猜想与验证
我猜想是JVM频繁作Full GC,致使进程也跟着频繁卡顿,处理消息的速度天然就慢了。为了验证这个想法,先用jstat看看内存使用状况:git
jstat -gcutil 1 1000 #1是进程号github
结果如我所料,几乎1秒钟就要作一次FGC,能安安静静的作个正常的consumer才有鬼了。缓存
赶忙留了一台consumer拿来作分析,把别的几台consumer都重启。无论怎样,先恢复消费能力再说!网络
内存泄露root cause排查
1秒一次FGC,那确定是发生内存泄露了。this
二话不说,把堆dump下来先!阿里云
jmap -F -dump:format=b,file=heapDump 1 #1是进程号.net
生成的heapDump文件有将近2个G的大小,这么大个文件,为了避免影响生产环境的机器,仍是scp到本地进行分析吧!3d
jhat了一下,直接卡在那里不动了。没办法,祭出VisualVM来帮忙。导入文件以后,发现有一大堆HashMap的Node在那占着:orm
然而并不知道这是个啥,点进去看看内容,发现有一大堆node的key类型是X509CertImpl:
这时候我意识到,问题可能出在网络链接上面。可是仍是无法定位到具体的代码。
没办法,接着向上找线索。不断地经过OQL查询Referrers:
接着查询:
接着查询:
这时候看到了链接池的踪影,感受离真相不远了!
到了这里,我内心大概知道了答案:问题必定出在阿里云OSS身上。再结合这张图:
就能够猜出是由于使用了OSS的客户端,可是没有正确的释放资源,致使client被回收时,它所建立的资源由于还有别的referrer, 却没有被回收。
再去oss github上的sample一看,果真有这么一段:
而这个shutdown方法作的正是释放Idle资源的事儿:
public void shutdown() { IdleConnectionReaper.removeConnectionManager(this.connectionManager); this.connectionManager.shutdown(); } 1 2 3 4 问题修复 知道了缘由,修复也是很轻松的事儿。 在建立client的缓存里加个removeListener,用来主动调用client.shutdown(), 美滋滋: