共计 1000 个字符,预计需要花费 3 分钟才能阅读完成。
一、背景
在进行本地测试时,发现调用某个服务时会偶现调用失败的问题,报错信息如下:
从图中可知,是从注册核心未找到服务导致。一开始认为是有人在重新部署,前面发现这个问题呈现的有些频繁,于是开始排查公布记录,发现近期并未有人重启服务,然而容器的重启次数高达 1521 次
二、问题跟进
首先想到两种起因:
- 容器网络呈现问题,导致健康检查失败,被 k8s 从新拉起
- 容器因为某些起因挂掉了,导致无奈响应申请(盲猜是 OOM 了)
第一种通过运维排查后排除。于是开始排查第二种状况,从监控上看到了 GC 回收工夫高达 30s
因为是个老服务,且外面逻辑泛滥,又没有主动生成 dump 文件的配置,无奈齐全必定是 oom 导致。于是批改了我的项目配置,将 Xms 和 Xmx
参数从 512m 批改为了 1024m,并增加上 oom 后主动 dump 的配置,从新公布了服务。
约半小时左右,服务又又又又重启了,这次捞到了对应的 dump 文件,开始进行剖析。
三、问题剖析
关上 jvisualvm,将 dump 文件导入,看到了如下提醒:
持续跟进,查看这个线程的状态,找到了对应的办法:
这是个简略的查问,依据 AgencyId 和 OrderId 进行查问,依照 id 进行倒序,而后在数据库中查问了下,发现因为没有创立索引,导致查问很慢。。。。
看似找到了问题,但有个疑难仍没有解决, 一个慢 sql 是怎么导致整个服务 OOM 的?。。于是开始持续深挖代码。
四、问题解决
最终排查了下代码,找到了最终的起因:
- 这个查问语句属于一个订单查问的定时工作,外面逻辑比较复杂,且这个工作每隔 2 分钟会执行一次
- 因为是个老服务,之前的定时工作是 http 申请触发,每次执行之前不会判断上一次是否执行实现。。
- 有个慢 sql(单次执行 18s 左右,定时工作中会循环执行这个 sql 查问数据),导致每次定时工作执行工夫很长,约 190s 左右
综合以上个性,曾经大抵猜到了问题产生的起因:
因为慢 sql 导致执行一次定时工作耗时较长,而后每隔 2 分钟会从新触发一次定时工作,导致多个定时工作逻辑同时执行,因为外部逻辑简单,最终导致内存耗尽,服务宕机,而后被 k8s 重启,周而复始。。。
dump 文件的内容,也证实了这个猜想,确定存在多个线程在执行这个定时工作,OOM 时总共有 12 个线程正在执行。。
解决办法也很简略粗犷,减少表索引,缩短每次定时工作的执行工夫,避免出现多个线程同时执行定时工作撑爆内存。
别问为什么不优化代码。。老服务,改不动啊改不动。。。