記錄一次線上服務CPU飆高問題

2023-07-26 18:00:39

2023.07.20 20:01:38線上一個服務發生了CPU過高的告警,

看告警資訊當前的CPU使用率已經達到了82.65%,問題已經很嚴重,趕緊開始排查起來。來複盤下如何排查這類問題,

一、排查方法

1、找到cpu過高的程序ID

收到告警後,第一件事要做的就是找到CPU過高的程式的執行緒id(pid),可以使用jps或ps -ef |grep java兩個命令均可,

1.1、jps

使用jps命令

jps

得到下面的結果

也就是程序ID是6。

再看使用ps的結果

1.2、ps

使用ps命令

ps -ef |grep java

得到下面的結果

可以看到程序ID也是6。

當然除了上面兩個命令,還可以使用top,也可以很快找到CPU過高的服務程序ID。

我們已經知道了cpu過高的服務程序ID是6,但僅知道程序ID是無用的,需要進一步知道這個程序中哪些執行緒佔用CPU過高。

2、找到cpu過高的執行緒ID

這裡使用的是top命令

top -Hp 6

得到的結果如下

可以看到執行緒1110 1125 1112 1121等佔用CPU過高,基本都在80%,基本可以斷定就是這些執行緒在佔用CPU。

找到佔用CPU過高的執行緒後,就要看下相應的堆疊資訊。

1.3、列印程序堆疊

使用jstack命令,jstack命令可以列印出程序的堆疊,通過堆疊資訊可以分析到執行緒的執行情況,

jstack -l 6

可以看到很多類似這樣的資訊,這些資訊中有一個很重要的那就是nid=0x11,這個是代表的執行緒ID,聰明的你也一定知道這裡是16進位制,和剛才使用top -Hp命令看到的不一樣,那裡是10進位制的。

為了找到執行緒佔用cpu過高的堆疊,需要把執行緒ID做一次進位制轉換,既由10進位制轉換為16進位制,

例,1110--》0x456    1125--》0x465

以0x465為例,在堆疊中查詢相應的執行緒堆疊,

1.4、查詢執行緒堆疊

使用0x465查詢其對應的執行緒堆疊

可以看到執行緒0x465的執行緒狀態是RUNNABLE,而且看到了很多正則的呼叫,繼續往下看,找到了呼叫的程式碼,

最後分析是由於死迴圈引起的執行緒佔用CPU過高。

上面是我把檔案下載下來進行的查詢,那如何生成堆疊檔案,可以使用下面的命令

jstack -l 6 > dump.txt

生成後下載到本地即可。

如果線上環境無法下載,則只能通過命令進行查詢

jstack -l 6 | grep -A 10 0x465

這樣便可以看到相應的內容了。

二、fastthread

有沒有覺得使用jstack命令匯出檔案後自己分析很麻煩,沒事有工具,可以使用fastthread。

其網址是:https://fastthread.io/

將jstack或者其他工具dump的堆疊檔案上傳到該網站同樣可以分析出結果。

將剛才的檔案上傳後,得到分析報告,由於是分析CPU過高,重點看cpu threads即可。

可以看到nativeId:1125即對應top -Hp出的執行緒ID,這裡fastThread已經進行了進位制轉換,無需手動操作了,很貼心。點選檢視完整的堆疊資訊即可分析出相應的問題。

三、總結

一般程式CPU過高,大多數和死迴圈有關,分析此類問題的一般步驟是,

1、使用jps/ps -ef |grep java/top等命令找到程序ID,即pid;

2、使用top -Hp pid 找到程序中佔用CUP的執行緒ID;

3、使用jstack列印堆疊;

4、使用執行緒ID在堆疊中找到對應的執行緒堆疊;

5、分析執行緒堆疊,找到問題;

 

參考:

(7條訊息) jstack命令解析_fightingD&W的部落格-CSDN部落格

Linux命令之Grep——文字搜尋 - 閱讀清單 - 騰訊雲開發者社群-騰訊雲 (tencent.com)

 

推薦閱讀

因為一條DDL,差點搞掛整個系統,這次真的長了教訓

一次性掌握innodb引擎如何解決幻讀和不可重複讀

花了半天時間,使用spring-boot實現動態資料來源,切換自如