记一次cpu跑满的故障解决过程

今天运维反馈,我们线上一个web项目,CPU负载非常高,导致其他项目都快不正常了,查看线上的cpu负载,看到cpu竟然被这个进程占用了800%以上,着实惊人。

当时的CPU负载图:

而正常状态下应该是:

运维在服务器top查询的结果如下图所示:

怎么回事呢?内存占用并不高,所以排除是内存漏洞或gc等问题,最有可能的原因,就是代码上有死循环。于是试着看代码。

    看了半天后,并没有发现有死循环的情况。竟然CPU看到该进程占用如此多的资源,那能否看到某个线程的使用情况呢?运维把内存dump下来以后,的确看到一些运行的线程,但看不出什么名目来。网上发现一篇好文章,《tomcat7高CPU问题》

原文就不赘述了,这里只引用其关键部分:

第一步,使用top命令,发现占用较高的进程及ID。(上面的截图即是)   

top

第二步,找到进程以后,查看进程中占用时间较长的线程信息

ps -mp PID -o THREAD,tid,time | sort -rn

下面是运行出来的截图:

第三步,根据线程信息TID,打印出线程堆栈信息,需要先得出TID的16进制表示

printf "%x\n" TID
jstack PID |grep XXX -A 30

下面是运行出来的截图:

这样就发现问题出现的具体代码了。我们的Filter中,有一个成员变量Map,这个Map会在初始化的时候,往里面put一些数据,而在put的时候,没有线程控制,那put会出现死循环吗?开始不敢相信,查看下面这些文章
http://coolshell.cn/articles/9606.html
http://xm-king.iteye.com/blog/962172
http://my.oschina.net/xianggao/blog/393990
http://coolshell.cn/articles/9606.html

总之是因为HashMap的多线程环境下,键的链表会形成环,导致后续的操作陷入死循环。解决的办法是:

1. Collections. synchronizedMap(new HashMap())
2. concurrent包下的 ConcurrentMap 系列 ConcurrentHashMap, ConcurrentSkipListMap
3. 同步锁 synchronized  方法级 、块级
4. concurrent.locks 包下的 Lock 接口
推荐大家使用在并发的情况下使用 ConcurrentHashMap 代替HashMap
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章