2026-08-25 17:00:50 +08:00
最近我在一台 Linux Web Server 上看到一個很反常的現象:CPU 使用率原本長期接近閒置,卻突然在最近幾天的同樣時段反覆出現接近 400% 的高負載,而且每次都持續一段時間,這篇文章整理整個排查過程,以及一些經驗分享:
平常 CPU 的使用率幾乎接近 0 ,不過這幾天監控圖上看到的 CPU 在特定某些時段的使用率大約是:
Max: 405%, Avg: 25%, Last: 397%
我的 /etc/crontab 裡面最可疑的是:
* * * * * roga task a
這個 task a
是一隻每分鐘執行一次的排程寄信程式,以往信件量都很小,所以很快就執行完畢。
假設是我內部的問題,使得一次執行時間變長,那可能會出現 process overlap 的情況,加上我沒有用 lock 機制,因此可能發生 process overlap,最後大量 process 同時存在。
10:00 task a
10:01 task a
10:02 task a
10:03 task a
10:04 task a
...
當 CPU 高的時候,可以先看看有哪些 process 正在執行。
ps -eo pid,ppid,user,%cpu,%mem,etime,cmd --sort=-%cpu | head -30這樣可以看到:
如果問題是上面提到的 cron overlap,很容易看到:
task a
task a
task a
task a
task a
task a
大量重複存在。
不過我實際上機器查問題的時候,並沒有觀察到這個現象。
我從 VM 主機商那邊看系統監控圖,把 CPU、Disk I/O、IPv4、IPv6 放在一起比較,最明顯的現象是:
CPU 約下午 4 點開始高負載
CPU 午夜前後恢復正常
Disk I/O 和 CPU 的表現一致
而網路流量並沒有出現同樣形狀的同步暴增。
因此可以合理地把網路因素的可能性往後排,我自己推測應該是:
本機 batch / DB / filesystem 工作
↓
CPU 大量運算
+
Disk I/O 大量活動
↓
持續數小時
↓
工作完成後同時恢復正常
可能的方向包括:
老實說,這類問題最大的麻煩是發生狀況的當下,我有很大機率都不在線上,所以我弄了一個監控的
cpu-watch.sh ,功能如下:
以下是 cpu-watch.sh 最後的版本:
https://github.com/roga/cpu-watch
這隻 script 在每個 INTERVAL
週期都會獨立量測下列指標:
BUSY_CPU:所有 CPU core 的非 idle、非 iowait CPU
時間總和。以 4-core 主機為例,400% 代表四個 core
都處於忙碌狀態。IOWAIT:等待 I/O 的 CPU 時間占總 CPU
時間的百分比;這部分不視為 idle。STEAL:被 hypervisor 取走的 CPU 時間百分比。DISK_READ 與 DISK_WRITE:彙總
/proc/diskstats 的活動量,單位為 KiB/s。若系統使用 stacked
device 或 partition,同一份 I/O 可能會被重複計入。只要任一已設定的條件連續 TRIGGER_COUNT
次量測成立,就會開始一個
incident。這個設計可以避免短暫雜訊造成誤判;預設連續兩次(約 10
秒)比原本固定等待 15 秒、只看 CPU 的作法更快回應。因此,即使
BUSY_CPU 不高,純 I/O 異常也可能建立 incident log。
平常量測時只會讀:
/proc/stat
/proc/diskstats
基本上不會造成明顯 disk I/O。
這隻 script 在偵測到異常時會在 /var/log/cpu-watch/
底下建立 log file 。
例如:
incident-20260825-162315.log
incident-20260826-160842.log
incident-20260827-161102.log
用日期時間設計的好處是只要看檔名就能知道 CPU 異常是不是每天都在同一個時間出現,也方便然直接進去特定的 log 檔抓問題。
vmstat然而 CPU 使用率高,不代表一定是 CPU 在拼命計算,加上
vmstat 的紀錄也可以區分到底是卡在哪
us = user CPU
sy = system CPU
wa = I/O wait
id = idle
舉例一:(CPU 真的在運算)
us sy wa id
85 10 1 4
舉例二:(在等 storage I/O)
us sy wa id
10 5 80 5
之後再根據時間點,找查 log ,這樣就更容易找出 root cause:
less /var/log/cpu-watch/incident-20260825-162315.log對偶發性的 server CPU spike 來說,這種「事件導向蒐證」會比一直寫大量監控 log 更有效率,只要設好臨界點,等條件觸發再寫紀錄就好了。