20191105中午12点左右线上报警。
通过gtrace,发现接口响应超时:
通过gtrace查看方法调用链:发现内存溢出。
于是迅速切到普罗米修斯监控:
发现服务从12点01分到04分之间不可用,但之后,在不重启服务的情况下,对外正常提供服务。并且各项指标正常。得出结论,不是堆内存泄露,而是堆内存溢出。
接下来就顺理成章的需要下载堆转储快照。比较坑的一点是,堡垒机不支持jmap,jstat命令。需要进入usr/local/env/jdk1.8目录下运行命令。
首先ps -ef|grep venus 得到pid 。37257
然后dump文件。./jmap -J-d64 -dump:format=b,file=dump.bin 37257 得到dump.bin文件
接着sz dump.bin 下载到本地。通过mat或者javaVisulVM工具具体分析。大对象产生原因。
关于mat分析的帖子:https://blog.csdn.net/XiaoHanZuoFengZhou/article/details/102930185
https://www.cnblogs.com/liuchuanfeng/p/8484641.html
关于Vm分析的帖子:https://blog.csdn.net/XiaoHanZuoFengZhou/article/details/102930219
通过一系列的分析:
发现绝大多数内存占用发生在一个Map里,里面装的是AccountProviderScopeDO。
然后定位代码:发现
当入参集合为空时,全表拉取。
至此,已经定位到之间原因。
接着分析,发现传进来的集合基本不会为空,因为这种操作是先写再读的。所以读的时候一定会有数据传入。
最根本原因定位到。主从延迟。写入主库成功,查询从库数据不存在。导致传入空集合,进而引发全表拉取。
修复方式:
建议:以后所有动态sql,考虑极端情况下的参数漏传,引起的全表扫描。