背景介绍
最近写的关于dubbo内存泄露稍微复杂了一点,很多人表示看不明白,想到之前遇到的比较简单的内存泄露问题,更容易入门,于是拿出来分享一下。
为了做微服务的熔断降级限流,引入了sentinel组件,对于sentinel引入到公司内部使用只是做了一些简单的定制化,如持久化配置规则,监控数据收集展示,后台登录权限整合等等。
在功能验证通过的情况下,也做了压测,性能符合要求,于是就推上了生产做线上灰度。刚开始没问题,直到有一天线上配置了一条降级规则,并且触发了,监控告警就炸了锅。
开始是服务出现大量慢请求,后来服务完全僵死。查看监控,慢请求很多,cpu飙升,full GC频繁,内存占满,日志中也出现了java.lang.OutOfMemoryError,可以断定是内存问题了。
问题排查
由于当时对系统的操作只有开启了降级规则,于是立马删除规则并重启,系统恢复,但并没有保存一份内存的dump文件。想着如果问题能复现就好查了,在当初的预发机器上试了一下,并没有复现。思前想去,难道跟机器有关?于是线上摘下一台机器来,配置规则,稍微压测一下,果然出现了问题。
能复现就好办,赶紧dump内存,很多人不知道怎么dump java的内存文件,可以使用jdk自带的jmap命令来dump,使用jmap dump内存时会触发一次full GC,所以线上使用要谨慎,full GC保证了dump出来内存里的对象都是存活的(无法释放)。
jmap -dump:format=b,file=dump.bin ${pid}
dump出来后的内存如果太大,可以使用tar命令压缩一下再下载到本地分析。分析工具使用eclipse的插件mat,它的官方地址如下
https://www.eclipse.org/mat/
从dump文件可以看到dubbo的线程每个都占用了2%的内存,该应用设置了200个线程,理论上已经把内存撑爆了。展开一个线程看看
该dubbo线