记一次CPU突然飙升到 100% 问题排查
线上 CPU 飚高问题该如何定位问题呢?
是因为线程太多,导致上下文切换?
还是因为应用代码中出现了死循环?
还是GC频繁导致 CPU 突然飙升?
该如何入手呢?
首先要知道那些情况会导致 CPU 的突然飙升:
- 频繁GC,访问量高时,有可能造成频繁的GC、甚至FGC。当调用量大时,内存分配过快,就会造成GC线程不停的执行,导致CPU飙高
- 序列化与反序列化,例如应用代码执行xml解析时,调用量增大的情况下,可能导致了CPU被打满
- 加密、解密
- 正则表达式校验(正则匹配回溯问题)
- 线程上下文切换、当启动了很多线程,而这些线程都处于不断的阻塞状态(锁等待、IO等待等)和执行状态的变化过程中。当锁竞争激烈时,很容易出现这种情况
- 某些线程在做无阻塞的运算,简单的例子while(true)中不停的做运算,没有任何阻塞。写程序时,如果需要做很久的计算,可以适当将程序sleep下
实际案例:
在一次生产切库时,暂停了 kafka 的消费,大概切了8个小时,导致 kafka 内堆积了大量的数据(ps:一些统计数据),当重新启动消费的时候,CPU 迅速打满。
排查问题:
因为在消费kafka时,使用了多线程进行消费,并且使用了 Executor 框架提供的 Executors.newFixedThreadPool(50),设置了 50,导致产生大量的线程在做上下文切换
vmstat 可以查看线程上下文切换的频率
vmstat 1 10
参考文章:Linux vmstat命令详解
将线程数降为6,CPU 恢复正常。
这是在明确知道可能出现CPU飙升出现的情况。
大多数情况下是不会明确知道问题出在哪里的?那该如何进行排查呢?
使用 top 命令查找 cpu 占比最高的线程
top
根据前面的 pid,使用 top -H -p pid 查看该进程的线程信息,查看是那个线程耗费 CPU
top -H -p pid
找到占用 cpu 最高的线程的 pid,例如 88
使用 printf “%x\n” 88,打印该线程的 16 进制数值
print “%x\n” 88
58使用 jstack 命令将进程 pid 的堆栈信息倒出来
jstack pid > pid.log
打开 pid.log, 查找 线程 nid 为 58 的线程即为 cpu 最高占用的线程。
tips
现在大部分应用都是使用docker运行,在查找的过程中,如何对应docker内的进程pid与宿主机的进程pid
使用 docker top name
如上 pid 即为该 docker 镜像在宿主机中的pid
一个可以在线分析堆栈信息的网站:https://fastthread.io/
还没有评论,来说两句吧...