線上故障排查(1) - Java應用故障之高CPU佔用的問題及排查方案
做為應用負責人,誰都希望自己負責的應用能夠在線上跑得順順當當,不出任何錯誤,也不產生任何告警,當然這是最理想的結果,也是做為技術人員希望達到的最終效果。可是實事上應用就像小孩一樣,總會在不經意間,不按你期望的結果執行,如CPU偏高、記憶體佔用偏高、應用沒有響應、應用自動掛掉等,搞得我們技術人員不是一般的頭大。我本人雖然身處管理崗位,也是處理在技術的第一線,也曾碰到過各種各樣的奇奇怪怪的問題,在此記錄下來,分享給給大家,今天第一篇分享是關於如何排查CPU偏高的問題。
以下是一段簡易的測試程式碼,用於模擬應用的CPU佔用偏高:
public class CpuUseTest { public static void main(String[] args) { new Thread() { public void run() { int result = 0; while (true) { result++; if (result > Integer.MAX_VALUE / 2) { result = 0; } } } }.start(); } }
大家應該都知道,單個CPU在同一時刻只能夠執行一個執行緒,如果某個執行緒一直無限的迴圈下去,其對這個CPU的佔用就不會釋放,會把這個CPU給佔滿,其它執行緒無法使用,如果電腦是單核的,那麼這個時候就會感覺到明顯的卡頓。
把這個應用給執行起來後,可以通過TOP命令檢視到其CPU的佔用情況如下:
可以看到其CPU佔用率達到了100%,這個時候我們當然希望找出這個CPU佔用偏高的程式碼位置,只有這樣我們才能夠解決這個問題。首先我們需要理解,Java是一個多執行緒應用,程序是由多個執行緒構成的,我們當前看到的是這個是這個程序的CPU佔用率,因而導致這個程序CPU偏高的是其中某個或某幾個執行緒,因而我們如果能夠找到這些執行緒那解決問題就好辦了。
在Linux環境下,可以通過ps命令(ps命令的詳細使用,請通過man ps命令獲取更多的幫助)檢視指定程序的執行緒情況,如下指令:
ps -mp 26541 -o THREAD,tid,time
可以檢視應用ID為26541的這個Java應用中,執行緒的CPU使用情況,結果如下:
可以看到程序號26541對應的執行緒tid為26561的執行緒,CPU佔用率達到了99.9%,因而我們只需要找出這個執行緒目前正在做的事情,那就好解決問題了。Java的JDK中有包括對應的執行緒堆疊檢視工具jstack,根據找到的執行緒ID 26561,就可以定位到CPU偏高的問題了。
注:通過ps命令檢視到的執行緒ID 26561是十進位制,在有的Java JDK裡面的jstack命令輸出的是十進位制的執行緒ID,有的是十六進位制的執行緒ID,這個需要使用者先通過jstack命令去查看了,如果是十六進位制的執行緒ID,可以通過如下命令將十進位制的執行緒ID轉換為十六程序的執行緒ID,如這裡將執行緒ID 26561轉換為十六進位制的命令如下:
fenglibin@fenglibin-HP:/home/fenglibin$ printf "%x\n" 26561 67c1
這裡得到的執行緒ID的十六進位制就是67c1,我的電腦中的jstack顯示的執行緒號是十六進位制的,因而就使用這個十六制了。通過如下命令可以找到導致當前應用CPU偏高的執行緒和其執行堆疊:
可以看到導致該執行緒CPU偏高的執行堆疊為測試程式碼中的第18行,也就是執行無限迴圈的程式碼塊所在的位置,直此導致該應用CPU偏高的問題,被成功定位。
後續我們繼續寫如何定位記憶體溢位的問題,如果感興趣,可以繼續觀注。