OOM(一):线上排查及解决流程

20191105中午12点左右线上报警。

通过gtrace,发现接口响应超时:

 

 

OOM(一):线上排查及解决流程_第1张图片

 

通过gtrace查看方法调用链:发现内存溢出。

 

 

OOM(一):线上排查及解决流程_第2张图片

于是迅速切到普罗米修斯监控:

OOM(一):线上排查及解决流程_第3张图片

OOM(一):线上排查及解决流程_第4张图片

 

 

发现服务从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。

OOM(一):线上排查及解决流程_第5张图片

然后定位代码:发现

OOM(一):线上排查及解决流程_第6张图片

当入参集合为空时,全表拉取。

至此,已经定位到之间原因。

接着分析,发现传进来的集合基本不会为空,因为这种操作是先写再读的。所以读的时候一定会有数据传入。

OOM(一):线上排查及解决流程_第7张图片

 

最根本原因定位到。主从延迟。写入主库成功,查询从库数据不存在。导致传入空集合,进而引发全表拉取。

修复方式:

OOM(一):线上排查及解决流程_第8张图片

建议:以后所有动态sql,考虑极端情况下的参数漏传,引起的全表扫描。

通过gtrace发现此次事故还有一个原因就是时间差:

 

 

OOM(一):线上排查及解决流程_第9张图片

 

OOM(一):线上排查及解决流程_第10张图片

 

 

该请求执行过程为:先查询主账户表,若不存在,则返回业务异常。若存在,去查账户表。

然而gtrace上显示12点0分10秒去查询15秒插入的数据。应该查不到,返回异常。从结果上来看,查到数据了,于是接着查账户表。

这一次没有查到,于是最后走入了动态sql。select * from provider_scope where is_deleted = 0 


 and account_id in
    
 #{accountId}
    

 

最终导致全表拉取数据,内存申请,分配不到内存,于是OOM。在近乎4分钟的时间,执行fullGC,stop the world。

你可能感兴趣的:(排坑)