Stories

Detail Return Return

線上CPU飆到100%?別慌,這3個工具比top快10倍! - Stories Detail

線上CPU飆到100%?別慌,這3個工具比top快10倍!

正準備下班,手機突然瘋狂震動——生產環境CPU告警!你SSH登上服務器,習慣性地敲下top命令,然後按H切換到線程視圖,找到最高CPU的線程,記下PID,轉成16進制,再jstack...等你一套操作敲完,5秒過去了,CPU使用率已經降下來了。線索,就這樣在指尖溜走。

🔥 傳統方法的三宗罪

説起定位Java應用CPU使用率高的問題,大部分人的第一反應是:top + jstack

完整流程是這樣的:

# 第一步:找到Java進程
top

# 第二步:切換到線程視圖
按 H 鍵

# 第三步:記下最高CPU的線程ID(比如12345)

# 第四步:轉16進制
printf "%x\n" 12345
# 輸出:3039

# 第五步:dump線程棧
jstack <pid> > thread.txt

# 第六步:在文件中搜索 nid=0x3039
grep -A 20 "nid=0x3039" thread.txt

看起來很專業?但有三個致命問題:

1. 命令長,記不住

老實説,你能背下printf "%x\n"這個16進制轉換命令嗎?反正我每次都要Google一下。遇到線上問題緊張得不行,大腦容易空白,這種命令根本記不住。

2. 流程長,容易出錯

6個步驟,任何一步出錯都要重來。線程ID記錯了?16進制轉換算錯了?grep的時候少打個0?每一步都是坑。

3. 時機錯過,白忙一場

這是最要命的。

CPU飆高往往是瞬時的——可能是某個定時任務觸發,可能是流量突增,也可能是GC導致。等你把上面這6步命令敲完,5秒過去了,CPU使用率已經降下來,線程棧里根本看不出問題所在。

就像拿着相機想拍流星,結果還在調焦距,流星已經沒了。

我去年就遇到過一次:電商大促期間,訂單服務CPU間歇性飆到90%,每次持續2-3秒。等我SSH登上去,top剛打開,CPU就降下來了。來來回回折騰了半小時,一無所獲,最後只能擴容服務器硬抗。

那次之後,我決定找更快的工具。

🚀 工具1:show-busy-java-threads.sh - 一鍵救場

為什麼推薦它?

show-busy-java-threads.sh是一個Shell腳本,把上面那6步操作自動化了。一行命令,秒級出結果。

完整的腳本鏈接,關注公眾號回覆 thread 可下載。

真實案例:秒級定位死循環

去年有一次,推薦服務的CPU突然飆到300%(4核機器),持續了10多分鐘。用户反饋首頁加載特別慢。

我第一時間想到了這個腳本:

# 直接運行,不需要傳任何參數
./show-busy-java-threads.sh

瞬間結果就出來了:

[1] Busy(57.0%) thread(23645/0x5c5d) stack of java process(23630):
"recommendation-worker-3" #123 daemon prio=5 os_prio=0 tid=0x00007f8a1c0a1000 nid=0x5c5d runnable
    at com.company.recommend.ContentFilter.isValid(ContentFilter.java:156)
    at com.company.recommend.RecommendEngine.filter(RecommendEngine.java:89)
    at com.company.recommend.RecommendEngine.process(RecommendEngine.java:45)
    ...

[2] Busy(55.2%) thread(23648/0x5c60) stack of java process(23630):
"recommendation-worker-6" #126 daemon prio=5 os_prio=0 tid=0x00007f8a1c0a3800 nid=0x5c60 runnable
    at com.company.recommend.ContentFilter.isValid(ContentFilter.java:156)
    ...

一眼就看出來了:

  • 多個工作線程都卡在ContentFilter.isValid這個方法的156行
  • CPU佔用分別是57%和55%

打開代碼一看,第156行是個正則表達式匹配,而且是在一個沒有break的循環裏...找到問題了!

從發現問題到定位代碼,很快就搞定。

使用方法

1. 運行腳本:

# 自動識別Java進程,顯示最繁忙的5個線程
./show-busy-java-threads.sh

# 顯示最繁忙的10個線程
./show-busy-java-threads.sh -c 10

# 指定Java進程ID
./show-busy-java-threads.sh -p 12345

# 持續監控模式,每3秒刷新一次
./show-busy-java-threads.sh -c 5 -i 3

2. 輸出解讀:

腳本會輸出:

  • 線程ID(十進制和十六進制)
  • CPU佔用百分比
  • 完整的線程棧
  • 自動高亮顯示業務代碼

優勢:

  • ✅ 不用記命令,一行搞定
  • ✅ 不用轉16進制,自動完成
  • ✅ 不用grep,直接顯示
  • ✅ 支持持續監控,不錯過瞬時高峯

適用場景:
適合在生產環境快速救場,尤其是CPU飆高持續時間較短的場景。放在服務器上常備,關鍵時刻能救命。

📊 工具2:fastthread.io - 在線分析專家

為什麼推薦它?

如果説show-busy-java-threads.sh是"急救箱",那fastthread.io就是"體檢中心"。

它是一個在線的線程棧分析工具,可以把jstack dump出的線程棧文件上傳上去,生成一份詳細的可視化報告。不僅能看CPU,還能發現死鎖、線程泄漏、阻塞等問題。

什麼時候用它?

當你已經用jstack dump了線程棧,但是:

  • 線程太多(幾千個),肉眼根本看不過來
  • 想分析線程的整體狀態分佈
  • 懷疑有死鎖或者阻塞
  • 想生成報告給其他人看

我一般會這樣用:

  1. 先用show-busy-java-threads.sh快速定位
  2. 如果問題不明顯,再用jstack dump完整線程棧
  3. 扔到fastthread.io深度分析

使用步驟

1. 生成線程棧文件:

# 獲取Java進程ID
jps -l

# dump線程棧(帶鎖信息)
jstack -l <pid> > thread_dump.txt

2. 訪問fastthread.io並上傳:

打開 https://fastthread.io/,把thread_dump.txt文件拖進去,幾秒鐘就能生成報告。

3. 查看分析報告:

報告包含這些內容:

① 線程總覽:

Total Threads: 156
Runnable: 8
Waiting: 120
Timed_Waiting: 25
Blocked: 3

② CPU熱點線程:
自動識別出佔用CPU最高的線程,按百分比排序。

③ 線程分組統計:
按線程名前綴分組,比如:

http-nio-8080-exec: 50 threads
scheduling-: 10 threads

能快速看出哪個線程池的線程最多。

④ 死鎖檢測:
如果有死鎖,會高亮顯示並畫出依賴關係圖。

⑤ 阻塞分析:
統計哪些線程在等待同一把鎖,幫你發現鎖競爭問題。

實戰技巧

技巧1:多次dump對比

CPU飆高時,連續dump 3次線程棧(間隔1秒),分別上傳到fastthread.io。如果某個方法在3次dump中都出現,基本可以確定就是它了。

jstack <pid> > dump1.txt
sleep 1
jstack <pid> > dump2.txt
sleep 1
jstack <pid> > dump3.txt

技巧2:關注RUNNABLE狀態

CPU高的時候,重點看狀態是RUNNABLE的線程。WAITINGTIMED_WAITING的線程不佔CPU。

優勢:

  • ✅ 可視化報告,一目瞭然
  • ✅ 自動檢測死鎖、阻塞等問題
  • ✅ 無需安裝,瀏覽器就能用
  • ✅ 支持多次dump對比分析

適用場景:
適合事後分析、深度排查、生成報告給團隊共享。對於複雜的線程問題(死鎖、線程泄漏),效果特別好。

🔧 工具3:Arthas - 阿里開源的診斷神器

為什麼推薦它?

Arthas是阿里開源的Java診斷工具,功能非常強大,堪稱"瑞士軍刀"。不僅能定位CPU問題,還能:

  • 反編譯線上代碼
  • 實時修改日誌級別
  • 查看方法調用耗時
  • 查看類加載信息
  • ...

我在之前的文章《線程暴增20K+!一次驚心動魄的Jenkins性能排查之旅》裏,就是用Arthas的classloader命令找到了問題的根源。

對於CPU問題,Arthas的thread命令特別好用。

使用方法

1. 安裝並啓動:

# 下載arthas-boot.jar
curl -O https://arthas.aliyun.com/arthas-boot.jar

# 啓動並attach到Java進程
java -jar arthas-boot.jar

啓動後會列出當前所有Java進程,輸入序號選擇要診斷的進程:

[INFO] arthas-boot version: 3.7.1
[INFO] Found existing java process, please choose one and input the serial number.
* [1]: 12345 com.company.Application
  [2]: 23456 org.elasticsearch.bootstrap.Elasticsearch
1

2. 查看CPU佔用最高的線程:

# 顯示CPU佔用最高的3個線程
thread -n 3

輸出示例:

"http-nio-8080-exec-123" Id=156 RUNNABLE (in native)
    at sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
    at sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
    at sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:93)
    ...

"background-task-2" Id=89 RUNNABLE
    at com.company.service.DataProcessor.process(DataProcessor.java:234)
    at com.company.service.DataProcessor.run(DataProcessor.java:156)
    at java.lang.Thread.run(Thread.java:748)

CPU佔用: 45.3%

3. 持續監控某個線程:

# 查看指定線程ID的詳細信息
thread 156

# 每3秒刷新一次
thread -i 3000

4. 查看所有線程的狀態分佈:

thread

會輸出:

Threads Total: 156, NEW: 0, RUNNABLE: 8, BLOCKED: 3, WAITING: 120, TIMED_WAITING: 25
ID    NAME                          GROUP           PRIORITY  STATE      %CPU    TIME
89    background-task-2             main            5         RUNNABLE   45.3    0:23.567
156   http-nio-8080-exec-123        main            5         RUNNABLE   12.1    0:08.234
...

優勢:

  • ✅ 實時交互,無需重啓應用
  • ✅ 功能豐富,一個工具頂十個
  • ✅ 不影響性能,可以在生產環境使用
  • ✅ 社區活躍,文檔齊全

適用場景:
適合複雜問題的深度診斷,尤其是需要實時交互、方法追蹤的場景。是每個Java工程師都應該掌握的神器。

📋 三個工具對比總結

工具 上手難度 速度 功能豐富度 使用場景
show-busy-java-threads.sh ⭐ 極簡 ⚡️ 秒級 ⭐⭐ 單一 生產環境快速救場
fastthread.io ⭐⭐ 簡單 ⚡️⚡️ 分鐘級 ⭐⭐⭐ 中等 事後深度分析、生成報告
Arthas ⭐⭐⭐ 需學習 ⚡️ 實時 ⭐⭐⭐⭐⭐ 最強 複雜問題診斷、實時監控

我的推薦:

  • 新手:先學show-busy-java-threads.sh,一行命令搞定90%的場景
  • 進階:學會fastthread.io,應對複雜的線程問題
  • 老手:必須掌握Arthas,這是Java工程師的核心競爭力

組合使用效果最佳:

  1. 問題發生時,先用show-busy-java-threads.sh快速定位
  2. 如果一次看不出問題,dump完整線程棧扔到fastthread.io分析
  3. 需要深度排查時,用Arthasthreadtracewatch等命令追蹤方法

💡 最後的建議

1. 別等出問題再學工具

很多人都是這樣:線上出問題了,才開始Google"怎麼定位CPU高",然後手忙腳亂。

正確做法:

  • 在測試環境提前把這三個工具裝好、玩熟
  • 寫個死循環程序,模擬CPU飆高,練習定位
  • 把常用命令整理成checklist,貼在工位上

關鍵時刻,肌肉記憶能救命。

2. 監控告警要先行

工具再好,也只是"事後諸葛亮"。更重要的是提前發現問題

  • 配置CPU使用率告警(建議閾值70%)
  • 配置JVM線程數告警
  • 配置接口響應時間告警

發現得越早,處理越從容。

3. 養成記錄習慣

每次排查完問題,記得寫個覆盤文檔:

  • 問題現象
  • 定位過程
  • 根本原因
  • 解決方案

不是為了寫而寫,是為了下次遇到類似問題,能快速找到解決思路。


📮 我是穩哥,深耕Java和中間件領域多年,專注分享實戰經驗和技術乾貨。

💡 關注我,一起探索:

  • 🔧 線上問題排查實戰
  • ⚡ 性能優化真實案例
  • 🎯 架構設計最佳實踐
  • 🚀 從原理到實戰的技術深度剖析

關注公眾號【穩哥的隨筆】,讓我們一起在技術的道路上不斷精進! 🚀

穩哥的隨筆

如果這篇文章對你有幫助,歡迎點贊、收藏、轉發,你的支持是我創作的最大動力!
user avatar mannayang Avatar xiaoniuhululu Avatar journey_64224c9377fd5 Avatar u_13529088 Avatar xuxueli Avatar lenglingx Avatar u_11365552 Avatar jiangyi Avatar lvlaotou Avatar jkdataapi Avatar boxuegu Avatar nianqingyouweidenangua Avatar
Favorites 60 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.