场景

系统突然运行缓慢,请求无响应导致页面卡死。

解决方案

如果 CPU 100% 导致服务不可用,简单应用可以在分析问题后收集 dump 日志用于分析,之后重启服务保证服务可用;多节点等复杂应用需要将其服务降级,隔离故障机器。

排查步骤

1、使用 top 命令查看占用 CPU 高的 Java 进程,记下进程 PID 29517
image.png

2、使用 top -Hp PID 命令查看该进程下各线程运行情况,发现有几个占用 CPU 比较高的线程
image.png

3、使用 jstack PID | grep TID 命令查看线程信息,TID 需要先转为 16 进制
image.png

情况一、Full GC

通过 jstack 命令查看发现是 VMThread,都是 GC 线程导致
image.png
使用 jstat -gcutil PID ms TID 命令查看 GC 情况,这里是一秒刷新一次。发现 FGC 确实很大
image.png

有可能是代码中某个地方不断创建处理 Bean 对象,系统频繁 Full GC 导致内存耗尽,通常可以看到异常信息:Exception in thread “pool-18-thread-24” java.lang.OutOfMemoryError: GC overhead limit exceeded)。
这时需要使用 jmap -dump:format=b,file=~/dump.hprof PID 导出日志,使用内存分析工具 MAT(https://www.eclipse.org/mat/)分析。

通过分析定位到一个查询,从数据库中一次查询了几十万数据但是未使用,频繁触发查询,频繁 Full GC 导致内存耗尽。

情况二、耗费CPU的计算

通过 jstack 命令发现是用户线程堆栈信息,可定位到对应的耗费 CPU 进行大量计算的代码。

情况三、偶尔出现接口耗时

此时无法通过线上 jstack 正常排查,定位思路是对这个接口进行压测,这个多个线程暴露出来的相同的 jstack 堆栈日志,就是问题所在。

情况四、某个线程长期处于TIMED_WAITING状态

正常的用户线程不会一直在 WAITING,如果多次通过 jstack 查看 TIMED_WAITING 状态的线程中有同一个,则可以定位到该线程的堆栈信息。

情况五、死锁

jstack 会直接在日志中打印出死锁的线程堆栈信息。