Linux CPU 100% 問題:一個 shell指令碼解決

故障排查步驟
2.1 確定高負載進程的 PID
首先,登入伺服器,使用 top
命令確認伺服器的具體情況,然後根據情況進行分析判斷。
通過觀察 load average 和負載評估標準(8核),可以確認伺服器存在高負載情況。觀察各進程的資源使用情況,可以看到 ID 為 682 的進程 CPU 百分比相對較高。
2.2 確定具體異常業務
這裡,我們可以使用 pwdx
命令根據 PID 找到業務進程路徑,進而定位責任人和專案:
可以得出,該進程對應資料平台的 web 服務。
2.3 定位異常線程和具體代碼行
傳統解決方案通常涉及 4 個步驟:
1. top 按 P 排序:1040 // 首先按進程負載排序,找到 maxLoad(pid)
2. top -Hp 進程PID:1073 // 找到相關負載線程 PID
3. printf "0x%x" 線程PID:0x431 // 將線程 PID 轉為十六進制,便於後續 jstack 日誌搜索
4. jstack 進程PID | vim +/十六進制線程PID - // 如:jstack 1040|vim +/0x431 -
但對於線上問題定位,每一秒都很寶貴,上述 4 個步驟過於繁瑣耗時。之前淘寶的 oldratlee 將上述過程封裝成一個工具:show-busy-java-threads.sh
,可以方便地在線上定位此類問題:
可以得出,系統中一個時間工具類方法的執行 CPU 百分比很高。定位到具體方法後,檢查代碼邏輯是否存在性能問題。
根因分析
經過前面的分析排查,最終確定了一個時間工具類的問題,導致伺服器負載和 CPU 使用率高。
- 異常方法邏輯:將時間戳轉換為對應的具體日期時間格式。
- 上層調用:計算從當天零點到當前時間的所有秒數,轉換為對應格式,並以集合形式返回結果。
- 邏輯層:對應資料平台即時報表的查詢邏輯。即時報表會定時查詢,單次查詢中存在多次(n 次)方法調用。
可以得出,如果當前時間為上午 10 點,單次查詢的計算次數為 10*60*60*n = 36,000*n 次,並且隨著時間增加,每次查詢的計算次數將隨著接近午夜而線性增加。由於即時查詢、即時告警等多個模組的大量查詢請求需要多次調用該方法,導致大量佔用和浪費 CPU 資源。
解決方案
定位到問題後,首先考慮的是減少計算次數,優化異常方法。經過排查,發現在邏輯層,方法返回的集合中的內容並沒有被使用,而是簡單地使用了集合的大小值。在確認邏輯後,通過新方法(當前秒數 – 零點秒數)簡化了計算,替換了被調用的方法,解決了計算次數過多的問題。上線後,觀察伺服器負載和 CPU 使用率,相比異常時期下降了 30 倍,恢復到正常狀態。至此,問題得到解決。
總結
在編碼過程中,除了實現業務邏輯外,還需要注意代碼的性能優化。能實現的業務需求,和能更高效、更優雅地實現,實際上反映了兩種完全不同的工程師能力和境界,後者也是工程師的核心競爭力。
代碼寫完後,多做 review,思考是否可以用更好的方式實現。在線上問題中不要忽視任何小細節!細節是魔鬼。技術同仁需要有刨根問底的欲望和追求卓越的精神,只有這樣才能不斷成長和進步。
通過利用強大的工具如 show-busy-java-threads.sh
,並遵循系統的故障排查方法,你可以快速識別和解決 Linux 伺服器上的 CPU 使用問題。始終追求優化的代碼性能,以確保系統的穩定性和效率。