突然收到运维告警邮件,线上的一台负责处理定时任务的服务器CPU飙升到了100%,立马放下手头工作开始了紧张的排查工作。
之前也写过一篇文章JVM调优之Java进程消耗CPU过高
使用 jps
或 ps -ef|grep java
命令确定想要分析的应用的进程编号
使用top -p 109023 -H
命令查看指定进程下的线程cpu占用比例,分析是具体哪个线程占用率过高,其中 109023 就是通过第一步确定下来的进程编号
从top命令列出来的线程信息中找出对应占用cpu很高的线程,并将线程号转化为十六进制的形式
printf "%x\n" 201106 得到对应的十六进制31192
从中选择占比较高的线程的编号(PID),并将该PID转换为16进制。通过jstack 109023 |grep 31192
通过该命令可以分析出线程的具体信息,再通过相应的解决方法来解决cpu占用过高的问题。
最终排查发现是之前有个人在定时任务这里埋了一个坑,导致了死循环而引发的问题,代码大致如下
public static void main(String[] args) {
int beginId = 1;
// 1.查出来所有需要处理的流水信息
List<Phone> needHandlePhoneList = listNeedHandlePhone(beginId);
if (needHandlePhoneList.size() == 0){
return;
}
// 2.开始处理
while (needHandlePhoneList.size() > 0){
// 执行逻辑...
// bug:总数数据库中只有3条待处理记录,第一次查出3条,最后一条的id是3,那么此处的beginId便为3
beginId = needHandlePhoneList.get(needHandlePhoneList.size()-1).getId();
// bug:上面查出来的beginId是3,在按照>=3去是数据库中查询,还是会查到一条记录,如此needHandlePhoneList始终不为空,产生死循环
needHandlePhoneList = listNeedHandlePhone(beginId);
}
}
private static List<Phone> listNeedHandlePhone(int beginId) {
/**
* select * from phone where id >= #{beginId} order by id limit 100
*
* >= 存在问题,与外部逻辑配合会产生死循环,需改成>
*/
return initPhoneList();
}