2023.07.20 20:01:38线上一个服务发生了CPU过高的告警,

记录一次线上服务CPU飙高问题-LMLPHP

看告警信息当前的CPU使用率已经达到了82.65%,问题已经很严重,赶紧开始排查起来。来复盘下如何排查这类问题,

一、排查方法

1、找到cpu过高的进程ID

收到告警后,第一件事要做的就是找到CPU过高的程序的线程id(pid),可以使用jps或ps -ef |grep java两个命令均可,

1.1、jps

使用jps命令

jps

得到下面的结果

记录一次线上服务CPU飙高问题-LMLPHP

也就是进程ID是6。

再看使用ps的结果

1.2、ps

使用ps命令

ps -ef |grep java

得到下面的结果

记录一次线上服务CPU飙高问题-LMLPHP

可以看到进程ID也是6。

当然除了上面两个命令,还可以使用top,也可以很快找到CPU过高的服务进程ID。

我们已经知道了cpu过高的服务进程ID是6,但仅知道进程ID是无用的,需要进一步知道这个进程中哪些线程占用CPU过高。

2、找到cpu过高的线程ID

这里使用的是top命令

top -Hp 6

得到的结果如下

记录一次线上服务CPU飙高问题-LMLPHP

可以看到线程1110 1125 1112 1121等占用CPU过高,基本都在80%,基本可以断定就是这些线程在占用CPU。

找到占用CPU过高的线程后,就要看下相应的堆栈信息。

1.3、打印进程堆栈

使用jstack命令,jstack命令可以打印出进程的堆栈,通过堆栈信息可以分析到线程的执行情况,

jstack -l 6

可以看到很多类似这样的信息,这些信息中有一个很重要的那就是nid=0x11,这个是代表的线程ID,聪明的你也一定知道这里是16进制,和刚才使用top -Hp命令看到的不一样,那里是10进制的。

记录一次线上服务CPU飙高问题-LMLPHP

为了找到线程占用cpu过高的堆栈,需要把线程ID做一次进制转换,既由10进制转换为16进制,

例,1110--》0x456    1125--》0x465

以0x465为例,在堆栈中查找相应的线程堆栈,

1.4、查找线程堆栈

使用0x465查找其对应的线程堆栈

记录一次线上服务CPU飙高问题-LMLPHP

可以看到线程0x465的线程状态是RUNNABLE,而且看到了很多正则的调用,继续往下看,找到了调用的代码,

记录一次线上服务CPU飙高问题-LMLPHP

最后分析是由于死循环引起的线程占用CPU过高。

上面是我把文件下载下来进行的查找,那如何生成堆栈文件,可以使用下面的命令

jstack -l 6 > dump.txt

生成后下载到本地即可。

如果线上环境无法下载,则只能通过命令进行查找

jstack -l 6 | grep -A 10 0x465

这样便可以看到相应的内容了。

二、fastthread

有没有觉得使用jstack命令导出文件后自己分析很麻烦,没事有工具,可以使用fastthread。

其网址是:https://fastthread.io/

将jstack或者其他工具dump的堆栈文件上传到该网站同样可以分析出结果。

记录一次线上服务CPU飙高问题-LMLPHP

将刚才的文件上传后,得到分析报告,由于是分析CPU过高,重点看cpu threads即可。

记录一次线上服务CPU飙高问题-LMLPHP

可以看到nativeId:1125即对应top -Hp出的线程ID,这里fastThread已经进行了进制转换,无需手动操作了,很贴心。点击查看完整的堆栈信息即可分析出相应的问题。

三、总结

一般程序CPU过高,大多数和死循环有关,分析此类问题的一般步骤是,

1、使用jps/ps -ef |grep java/top等命令找到进程ID,即pid;

2、使用top -Hp pid 找到进程中占用CUP的线程ID;

3、使用jstack打印堆栈;

4、使用线程ID在堆栈中找到对应的线程堆栈;

5、分析线程堆栈,找到问题;

参考:

(7条消息) jstack命令解析_fightingD&W的博客-CSDN博客

Linux命令之Grep——文本搜索 - 阅读清单 - 腾讯云开发者社区-腾讯云 (tencent.com)

推荐阅读

因为一条DDL,差点搞挂整个系统,这次真的长了教训

一次性掌握innodb引擎如何解决幻读和不可重复读

花了半天时间,使用spring-boot实现动态数据源,切换自如

记录一次线上服务CPU飙高问题-LMLPHP

07-29 06:53