问题描述
在某一天系统更新上线一个版本后,运维人员通过监控发现服务器出现CPU使用率超过200%的问题,导致监控系统频繁告警。
排查过程
我们的Tomcat是部署在linux环境中,下面的排查过程均在linux下进行。
1. 查看后台服务
通过查看Tomcat的后台日志,发现日志正常打印,未发现异常信息。
2. 查看服务器信息
2.1 找出耗CPU的进程
使用top命令查看特定用户(user1)的内存、cpu及各进程的信息:
[root@localhost ~]# top -u user1
使用上面的命令,可以看到下面的信息:
从上图可以看到存在一个java的进程CPU使用率很高,超过了200%的数值。
PS:从图中可以看到PID为150252(PID即为java进程ID),用户为user1,%CPU、%MEM分别表示CPU、内存的使用率
2.2 确认进程信息
[user1@localhost ~]$ jps -m # 使用jps命令可以快速找到java进程的PID
[user1@localhost ~]$ ps -fu user1 | grep tomcat # 使用ps指令可以找到PID为150252为tomcat进程
通过上面使用top命令找到了CPU使用率过高的进程,通过jps可以确认是Tomcat进程。
2.3 找出耗CPU的线程
1)找到耗用最高的线程和占用CPU的时间
[user1@localhost ~]$ ps -mp PID -o THREAD,tid,time
或者
[user1@localhost ~]$ top -Hp PID
PID即2.1中找到的进程id(150252),上图指令就是为了找出该进程下的线程信息。如下图:
PS:上图中的PID是线程ID,找到%CPU使用率较高的线程逐一分析。
2)把该线程ID转化为16进制
[user1@localhost ~]$ printf "%x\n" TID #将线程的TID转换成十六进制
3)从jvm堆栈中查找线程信息
在第2步中找到了耗时较高的线程ID,下面通过JVM的堆栈信息找到线程信息,使用下面的命令可以获得JVM的堆栈信息:
[user1@localhost ~]$ jstack PID | grep TID -A100
这里的PID代表的是Tomcat进程ID,TID是16进制表示的线程ID,线程堆栈信息如下:
从上面可以看到是一些线程信息,通过上图红框中的状态为RUNNABLE的线程信息,即为正在运行的线程,从这里可以找到相关的信息,接下来就是分析你的代码,这里是因为代码中使用了类似于while死循环导致的。
总结
CPU使用率过高的原因,大概有以下几种情况:
1、Java 内存不够或溢出导致GC overhead问题,GC overhead 导致的CPU 100%问题;
2、死循环问题,如常见的HashMap被多个线程并发使用导致的死循环 或者 死循环代码;
3、某些操作一直占用CPU
大多数都是因为线程无法终止或出现死循环等原因,但是仍然需要根据实际情况,具体问题具体分析。