背景
我負責的其中一個項目在空負載的情況下,CPU占用率依然保持着100%左右,線上、測試、開發的服務都一樣;是什么導致的呢?在開發環境我查看了請求流量,這個流量可以忽略但CPU占用率一直在60%-100%之間浮動。
分析問題
流量可以忽略,但CPU占用依然極其高說明不是請求多導致的資源占用,原因應該是項目本身自發導致的;自發包括定時任務與死循環,而具體哪一段代碼現在也確定不了。現在我們就可以借助原生的jdk分析工具來定位是項目哪塊出現了問題(你可以用更高級的jprofilter等,一連接,問題一目了然),以下我就采用jdk自帶工具jstack、jstat 、jmap等來逐步定位。
定位問題
- 在Linux環境下用top查看cpu、內存等資源占用情況(可采用: top -p pid 具體查看某個應用)。發現pid=4179的java應用占用cpu很高

- 查看pid=4179的應用各個線程占用cpu的時間片情況:ps -mp 4179 -o THREAD,tid,time (ps -mp pid -o THREAD,tid,time)。發現tid =4528的線程一直長時間占有着cpu並且占用率達100%

- 將 4528轉為16進制,便於在堆棧信息中查詢定位代碼塊:printf "%x\n" 4528,轉成16進制為 11b0

- 在堆棧信息中定位報錯代碼塊:jstack 4179|grep 11b0 -A 30 ( jstack pid|grep TID(16進制) -A 30 )
總結
從堆棧信息中我們可以看到是 WAITING導致,這個說明有一個線程長時間占用資源,而其他線程一直處於等待的狀態。最終定位出是在一個分布式鎖實現的模塊中有一個保持鎖的代碼塊有問題。然后通過優化這個分布式鎖最終解決了這個問題。通過此次優化,大大節省出了服務器資源(目前這個系統在線上是4台集群,相當於節省了1*4 個cpu,如果是一個上百甚至上千的集群,那么這個資源占用是無法想象的),最主要的是避免了這種情況對系統本身的影響,避免了對正常請求的阻塞。
