記一次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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章