暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

记录一次研发环境cpu100%的问题

不堪提 2022-05-12
196

点击蓝字关注我们

五一回来后,发现某微服务无法响应,出现卡死的现象。

重启后正常,过一段时间后就又会出现上文提到的现象。遂深入调查,并作文记录于下。



追踪服务日志

排查任何问题都先看日志,发现触发无响应的时候并无特殊日志提示,一切正常。


锁定服务进程

首先需要确定是哪个服务导致的cpu100%,使用命令

top -c

可以显示当前进程的运行列表,默认是按照 CPU 的使用率进行排序,即可找到占有cpu最高的进程的PID 。


锁定服务线程 

然后根据进程的PID,去查找是哪个线程占用cpu最多。使用命令

 top -Hp  【进程的PID

找到这个进程对应的线程,默认按照 CPU 的使用率进行排序,即可找到占有cpu最高的线程。 


打印线程的堆栈信息 

先将上一步查出来的线程PID转换成16进制。 

printf "%x \n" 【线程的PID】 

紧接着通过jstack命令打印堆栈信息 

jstack 【进程PID】 | grep '【16进制的线程的PID】' -C 50 


追踪堆栈信息 

走到这里,如果看到堆栈里面有大量的WAITING状态,或者提示有死锁,根据堆栈信息就会定位到自己的代码行数了。


但是在我这次并没有找到团队开发的代码,全都是依赖第三方jar的堆栈信息。

本次尝试并没有结果,放弃了。决定尝试其他的手段。 


打印堆快照 

jmap -dump:format=b,file=/usr/local/test.hprof 【进程PID】 

然后将生成的文件导入到Java VisualVM中,Java VisualVM是JDK的bin目录下自带的工具,可以通过JMX协议连接JAVA进程进行监控,也可以通过导入堆快照的方式用来分析堆内情况。 


发现一个动态代理生成的跟日志相关的类占有了大量的堆空间。 


下图为正常的堆空间 


可以看到正常的堆空间字符串占有的是最多的,因此定位到可能是由于堆空间设置的太小了,导致堆空间不足,于是接下来借助下GC日志观察下情况。

在JAVA_OPTS中添加以下内容

-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:./gclogs -XX:+PrintTenuringDistribution -XX:+PrintHeapAtGC 


可以看到JVM在频繁地触发了Full GC,触发Full GC后,会进入STW状态。

进入STW状态后,整个JVM的线程都会暂停,此时对于外界来说就是服务无响应了。


此外还观察到Metaspace的空间满了。

进入到服务的启动脚本中,观察当前使用的JAVA_OPTS参数

JAVA_OPTS="-XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=128m -Xms1024m -Xmx1024m -Xmn256m -Xss256k -XX:SurvivorRatio=8 -XX:+UseConcMarkSweepGC"

很可能是由于元空间设置的太小,而动态代理生成的类的结构信息正好就在这里面,存不下了,导致了Full GC。


删除参数启动后,经过一段时间后发现一切正常,破案了。


之前还在奇怪,为什么之前没问题,最近突然出现了这个情况,代码并没有提交什么奇怪的地方,看来是之前元空间就基本快满了,又加了些代码之后,云空间不够用了导致的,当然我们使用的Log4j也肯定哪里有问题,或者就是我们使用的哪里不对,待后续继续排查。 




点击关注,永不迷路

微信公众号:@不堪提





文章转载自不堪提,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论