这两天遇到一个服务假死的问题,具体现象就是服务不再接收任何请求,客户端会抛出BrokenPipe。
执行top,发现CPU和内存占用都不高,但是通过命令
netstat-n|awk'/^tcp/{++S[$NF]}END{for(ainS)printa,S[a]}'+发现有大量的CLOSE_WAIT端口占用,继续调用该服务的api,等待超时之后发现CLOSE_WAIT的数量也没有上升,也就是说服务几乎完全僵死。
怀疑可能是线程有死锁,决定先dump一下线程情况,执行
jstack
这就比较奇怪了,继续想是不是GC导致了STW,使用jstat查看垃圾回收情况
app@server:/tmp$jstat-gcutil1200010+S0S1EOMCCSYGCYGCTFGCFGCTGCT+0.0027.7965.0115.3094.7592.23133844.3751881475.064519.439+一看吓一跳,FGC的次数居然超过了YGC,时长有475s。一定是有什么原因触发了FGC,好在我们打开了GClog。
由于外部API暂时无法联系对方修改,所以为了先解决问题,对原有的MaxNewSize进扩容,从192MB扩容到一倍。经过几天的观察,发现gc基本趋于正常
S0S1EOMCCSYGCYGCTFGCFGCTGCT+0.003.3760.558.6095.0892.98872.42100.0002.421+扩容之前对heap进行了dump
jmap-dump:format=b,file=heapDump
分析了线程数量,大约是240多条,与正常时也并没有很大的出入。而且大量的是在sleep的定时线程。
本次排查其实并未找到真正的原因,间接表象是FGC频繁导致服务假死。而且acturator端口是正常工作的,导致healthcheck进程误认为服务正常,没有触发告警。