題幹與適用情境
一台具有 16 個邏輯 CPU 的 Linux 伺服器回應變慢,uptime 顯示 Load Average 為 48 / 36 / 18,但 mpstat 顯示整體 CPU idle 仍有 72%。請判斷這是否代表 CPU 過載,並說明如何找出真正等待的資源。
回答需要解釋 Linux 負載計量中的可執行工作與不可中斷睡眠工作,正確解讀 1、5、15 分鐘三個值,再用工作狀態、Pressure Stall Information(PSI)與子系統指標區分以下情況:
- CPU 執行佇列確實壅塞;
- 本機儲存、網路檔案系統、驅動程式或其他核心等待讓工作長時間處於 D 狀態;
- 記憶體回收或 swap 間接造成等待;
- 主機層級指標與容器或服務層級指標的範圍不同。
這是一道適合 SRE、DevOps、基礎設施、系統軟體與後端職缺的 Linux 診斷題。16、48、36、18 與 72% 都是虛構的練習資料,不是通用告警門檻。題目假設指標來自同一台主機、同一時間窗;若資料來自不同收集器或不同 cgroup,必須先對齊口徑。
面試官考察點
第一,候選人是否知道 Load Average 不是 CPU 使用率。Linux 的全域負載是可執行工作與不可中斷睡眠工作數量的指數衰減平均。只有前一部分直接表示 CPU 需求,後一部分可能在 CPU 閒置時仍把負載推高。
第二,能否精確解釋三個數字。它們不是最近 1、5、15 分鐘樣本的簡單算術平均,而是具有相應時間常數的指數衰減值。48 > 36 > 18 支持「近期負載正在上升」這個方向性判斷,但不能反推出某一分鐘的精確佇列長度,也不能單獨證明根因。
第三,診斷是否從「總數」走向「組成與等待位置」。好的回答會比較 vmstat 的 r、b,統計 R 與 D 狀態的執行緒,再從 wchan、核心堆疊、PSI 與儲存或網路檔案系統指標,把等待定位到具體資源。只說「執行 top、iostat」沒有說明證據如何改變結論。
第四,候選人是否會處理反例。D 狀態常被工具稱為 disk sleep,但不可中斷等待不只可能來自本機磁碟;NFS、檔案系統、裝置驅動程式與部分核心資源等待也可能出現。%iowait 是 CPU 時間口徑,低 iowait 不能排除工作已經阻塞。
最後看是否有安全的處置與驗證閉環。擴充 CPU、重新啟動、終止行程或升級磁碟,各自只適用於特定證據。修復後需要證明 R/D 工作、PSI、子系統延遲與業務尾端延遲一起恢復,不能只等待 Load Average 緩慢下降。
回答前需要澄清的問題
- 指標範圍一致嗎? Load Average 通常是主機全域值,而應用程式 CPU 可能只統計一個容器或行程。若範圍不同,先查看主機、cgroup 與服務三層指標,否則「高負載低 CPU」可能只是觀測口徑錯位。
- CPU idle 是整體平均還是每核心資料? 單一核心、NUMA 節點或受 CPU affinity 限制的工作可能已經排隊,而其他核心閒置。需要查看
mpstat -P ALL、親和性與 cgroup CPU 配額。 - 變慢的是哪些請求,何時開始? 對齊部署、流量、備份、儲存抖動、掛載變更與記憶體回收時間,才能把主機訊號與使用者影響連起來。
- R 狀態還是 D 狀態占主導? R 多且 CPU 忙支持 CPU 競爭;D 多且 CPU 閒置支持不可中斷等待。兩者可以同時存在,必須按執行緒與工作負載分組。
- 底層儲存是什麼? 本機 NVMe、雲端磁碟、區塊裝置、FUSE、NFS 與資料庫遠端呼叫需要不同證據。
iostat看不到一般網路 RPC,NFS 還需要掛載與網路檔案系統指標。 - 是否有記憶體或虛擬化壓力? swap in/out、直接回收、major fault、宿主機 steal time 與 cgroup 限制會改變診斷優先順序。
- 能否讀取工作堆疊?
/proc/12345/stack、部分wchan與行程 I/O 資料可能受權限限制。正式環境排查要使用最小必要權限,並先做低開銷取樣。
30 秒回答框架
「Load Average 不是 CPU 百分比。Linux 統計可執行工作與不可中斷睡眠工作的數量,並計算 1、5、15 分鐘時間常數的指數衰減平均。16 個邏輯 CPU 上負載 48 只能說明有很多活躍或不可中斷等待的工作;CPU 仍有 72% idle,不能直接斷言 CPU 飽和。
我會先確認指標範圍與每核心使用率,再用 vmstat 看可執行佇列 r 與阻塞工作 b,統計執行緒的 R/D 狀態。R 多、CPU PSI 高且 CPU 忙,才像 CPU 排隊;D 多、I/O PSI 高時,再用 wchan、工作堆疊、pidstat、iostat、NFS 與核心日誌定位等待資源。若 memory PSI、swap 與 major fault 同時升高,就轉查記憶體壓力。修復後同時驗證業務 p99、R/D 數量、PSI 與子系統延遲,不只等待負載數字下降。」
分步驟深入解答
第一步:先把 Load Average 拆成兩個來源
Linux 核心計算全域負載時,核心輸入可以概括為:
nrrunning + nruninterruptible
nrrunning 包含正在 CPU 上執行,以及已可執行、等待排程的工作;nruninterruptible 表示不可中斷睡眠工作。/proc/loadavg 的前三項是這組活躍工作數量的 1、5、15 分鐘負載值。第四項形如 7/1280,前一個數字是目前可執行的排程實體數量,後一個是目前存在的排程實體總數;第五項是最近建立行程的 PID。
因此,「負載 48」不是「CPU 使用率 300%」,也不是某一時刻恰好有 48 個行程排隊。它是經過平滑處理的工作數量訊號。將負載除以邏輯 CPU 數,只能作為純 CPU 型負載的粗略飽和提示;D 狀態工作較多時,這個比值不再表示 CPU 佇列程度。
核心按固定週期更新指數衰減平均。新樣本權重較高,舊樣本逐漸衰減,所以 48 / 36 / 18 表示近期活躍工作比更早時期多。即使根因已消失,15 分鐘值也會落後;恢復判斷應優先看即時工作狀態、PSI 與業務指標。
第二步:確認範圍、每核心使用率與即時佇列
先做一組低開銷取樣,並保留時間戳記:
nproc
uptime
cat /proc/loadavg
vmstat 1 10
mpstat -P ALL 1 10vmstat 第一行通常是自開機以來的平均,診斷目前問題時應看後續取樣。關鍵欄位如下:
r:可執行工作數量;持續明顯高於可用 CPU 並伴隨 CPU busy,支持 CPU 排隊;b:處於不可中斷睡眠的工作數量;持續升高時優先調查等待資源;us、sy、id、wa、st:區分使用者態、核心態、閒置、I/O wait 與虛擬機被搶占時間;si、so:swap in/out 活動,需要與 memory PSI 和 fault 一起判斷。
整體 72% idle 仍可能掩蓋單核心熱點。若一個序列執行緒固定在 CPU 3,CPU 3 可以接近飽和,而其他 15 個 CPU 大多閒置。此時查看每核心使用率、工作親和性、容器 CPU 配額與 throttling,比盲目增加整台主機 CPU 更有區分力。
第三步:按執行緒統計 R 與 D,找出等待點
行程內的多個執行緒都會參與負載計量,因此要使用執行緒檢視:
ps -eLo state,pid,tid,ppid,wchan:32,comm --sort=state
ps -eLo state= | sort | uniq -cR 表示正在執行或可執行。D 表示不可中斷睡眠;訊號通常要等工作離開該等待後才能生效,所以反覆執行 kill -9 既不能立即釋放等待中的核心資源,也會破壞現場。
對集中出現的 D 狀態執行緒,按命令、父行程、cgroup 與 wchan 分組。wchan 顯示執行緒在核心中睡眠的位置,能把範圍縮小到區塊 I/O、NFS、檔案系統或驅動程式路徑。權限允許時,再讀取代表性執行緒的核心堆疊:
cat /proc/12345/stack
cat /proc/12345/wchan單一函式名稱仍不是根因。相同 wchan 大量聚集、同一時間對應子系統延遲與業務變慢,才能形成較強證據。D 狀態也不能自動歸因於應用程式發起大量 I/O;裝置故障、遠端掛載失聯或核心路徑卡住,都可能讓少量請求累積成大量等待執行緒。
第四步:用 PSI 判斷哪一類資源讓工作停止推進
PSI 直接量化 CPU、記憶體與 I/O 爭用造成的停頓時間:
for resource in cpu io memory; do
echo "[$resource]"
cat /proc/pressure/"$resource"
donesome 表示至少有部分工作因該資源停頓的時間占比,full 表示所有非 idle 工作同時停頓的時間占比;系統層級 CPU full 保留為零,不應用它判斷 CPU 飽和。avg10、avg60、avg300 分別提供近 10、60、300 秒趨勢,total 是累計停頓微秒數。
PSI 與 Load Average 回答不同問題:Load Average 告訴你有多少活躍或不可中斷等待工作,PSI 告訴你工作負載有多少時間無法推進。兩者結合能避免「負載高就擴 CPU」的誤判。使用 cgroup v2 時,還應讀取目標 cgroup 的 cpu.pressure、io.pressure 與 memory.pressure,把服務本身壓力與主機雜訊分開。
可以用以下矩陣組織證據:
| 觀測組合 | 首要假設 | 下一步證據 | |---|---|---| | CPU busy 高、r 高、CPU PSI 高 | CPU 執行佇列競爭 | 每核心熱點、CPU profile、親和性與配額 | | CPU idle 高、b/D 多、I/O PSI 高 | I/O 或核心不可中斷等待 | wchan/堆疊、裝置或 NFS 延遲、核心日誌 | | memory PSI 高、si/so 或 major fault 增加 | 記憶體回收或 swap 壓力 | cgroup memory、工作集、回收與儲存讀寫 | | 主機負載高、目標 cgroup PSI 低 | 範圍錯位或其他租戶影響 | 按 cgroup/行程歸屬拆分工作與資源 |
這張表是調查起點,不是自動根因判定器。CPU、記憶體與 I/O 壓力可能形成回饋,例如記憶體回收引發檔案讀寫,再把執行緒推入 D 狀態。
第五步:進入對應子系統,不把所有等待都稱為「磁碟慢」
若證據指向區塊裝置,觀察裝置吞吐、延遲、佇列與錯誤:
pidstat -d -p ALL 1 10
iostat -xz 1 10
dmesg -T | tail -200pidstat 協助定位發起 I/O 的行程,iostat 報告裝置與分割區負載。任何欄位都需要結合裝置類型與基線解讀;例如裝置 %util 不能跨所有儲存架構使用同一個飽和門檻。核心日誌中的 timeout、reset、檔案系統錯誤或裝置脫離,比單獨的高佇列更接近故障原因。
若 wchan 或掛載點指向 NFS、FUSE 或網路儲存,要檢查掛載狀態、nfsiostat、用戶端重傳、網路延遲與伺服器端健康。一般 HTTP 或資料庫 RPC 等待通常處於可中斷睡眠,不一定進入 Linux Load Average;因此還需要把應用程式追蹤、連線池與相依服務延遲放進同一時間軸。
若 memory PSI、swap 或 major fault 上升,繼續檢查 cgroup 記憶體事件、匿名與檔案工作集、直接回收和 swap 裝置。只增加磁碟效能可能降低 swap 代價,卻沒有修正工作集超過記憶體預算的原因。
第六步:根據證據止損,並驗證因果關係
處置要對應已確認的等待資源:
- CPU 佇列競爭:限制入口、降低並行度或批次工作優先權,解除錯誤親和性,必要時按實測容量擴充 CPU;
- 儲存或 NFS 故障:停止繼續放大 I/O,切換健康副本或掛載路徑,修復裝置、網路或伺服器端;
- 記憶體壓力:限制工作集與並行度,停止造成 thrashing 的工作,在相容的容量邊界內擴充記憶體;
- 範圍錯位:先隔離雜訊工作負載或修正 cgroup 配額,再評估目標服務是否需要擴充。
重新啟動可能清除累積工作,也可能遺失關鍵堆疊與日誌;若底層資源仍不可用,新行程會再次阻塞。採取動作前保存代表性 PID、執行緒狀態、wchan、PSI 與子系統快照,並寫下預期變化。
驗收至少包含:業務 p95/p99 與錯誤率恢復;R/D 數量回到基線;對應 PSI 趨勢下降;裝置、NFS、記憶體或 CPU 指標恢復;佇列與積壓被安全處理。Load Average 的指數衰減會產生延遲,所以它是恢復證據之一,不是關閉事故的唯一門檻。
高品質示範回答
「我不會因為 16 個 CPU 上負載 48 就直接說 CPU 過載。Linux Load Average 平滑統計正在執行或等待 CPU 的工作,以及不可中斷睡眠工作。CPU idle 還有 72%,代表負載很可能包含大量 D 狀態等待,或整體平均掩蓋了單核心、配額或指標範圍問題。
48 / 36 / 18 是三個指數衰減平均,方向上表示近期活躍工作增加,不是三個簡單時間窗的算術平均,也不能告訴我根因。我先確認 Load、CPU 與業務延遲來自同一主機和時間窗,再看 mpstat -P ALL,排除單核心熱點與 steal time。
下一步用 vmstat 1 看 r 與 b。如果 r 持續高、CPU busy 與 CPU PSI 也高,我會從 CPU profile、親和性與 cgroup throttling 排查。如果 b 高、D 狀態執行緒很多但 CPU 仍閒置,我會按命令與 wchan 彙整執行緒,選擇代表性執行緒查看 /proc/12345/stack,再與 I/O PSI 對齊。
假設大量執行緒都停在 NFS 相關等待,I/O PSI 同時上升,本機區塊裝置的 iostat 卻正常,我會轉查掛載、用戶端重傳、網路與 NFS 伺服器端,不會升級本機雲端磁碟。止損可能是停止相關批次工作、把讀取切到健康副本或摘除故障節點;直接反覆終止 D 狀態行程通常不會立即生效。
修復後,我會驗證業務尾端延遲與錯誤率、R/D 執行緒數、cgroup 與主機 PSI、NFS 延遲和積壓都恢復。1、5、15 分鐘負載會隨時間衰減,因此即使 15 分鐘值仍高,只要即時等待與使用者結果已穩定,也不應為追求一個立刻變小的數字繼續做高風險操作。」
常見錯誤
- 把 Load Average 當 CPU 使用率 → 它統計工作數量,並包含不可中斷睡眠 → 先拆分
r與b、R 與 D,再判斷 CPU 競爭。 - 看到負載超過 CPU 數就宣布過載 → 這個規則只對 CPU 型負載有粗略提示價值 → 結合 CPU busy、CPU PSI 與可執行佇列。
- 把 1、5、15 分鐘值當簡單窗口平均 → Linux 使用指數衰減,舊樣本會逐漸保留 → 只用三值判斷方向,並用即時指標確認目前狀態。
- 把所有 D 狀態都歸因於本機磁碟 → NFS、檔案系統、驅動程式與其他核心等待也可能進入不可中斷睡眠 → 沿
wchan、堆疊與對應子系統指標定位。 - iowait 低就排除 I/O → iowait 是 CPU 時間統計,不等於等待工作數量 → 查看 D 狀態、I/O PSI、裝置與遠端儲存延遲。
- 只看主機平均 CPU → 單核心熱點、親和性、配額或其他 cgroup 會被平均掩蓋 → 比較每核心、主機與目標 cgroup。
- 反覆
kill -9卡住的工作 → 訊號要等不可中斷等待返回後才會處理,現場還可能被破壞 → 先保存證據並修復被等待的資源。 - 把一條
wchan當成根因 → 它只顯示目前核心睡眠位置 → 要求大量工作聚集、時間相關性與子系統異常互相印證。 - 只等 Load Average 歸零才宣布恢復 → 指數衰減會落後,正常系統也不要求負載為零 → 以使用者結果、即時工作、PSI 與資源指標共同驗收。
追問及應對
追問一:CPU idle 很高,為什麼 %iowait 也可能很低?
%iowait 表示 CPU 處於 idle 且系統認為有未完成 I/O 的時間比例,它是 CPU 記帳口徑。工作可以阻塞在 NFS、驅動程式或其他不可中斷核心等待,而 CPU 同時執行其他工作或保持一般 idle;多核心系統的彙整也會稀釋局部現象。應用 D 狀態數量、I/O PSI、wchan 與子系統延遲驗證,不能用低 iowait 單獨排除 I/O 或核心等待。
追問二:容器裡看到的 Load Average 能代表這個容器嗎?
不能預設代表。負載值與 /proc 的可見範圍取決於宿主機、PID namespace、執行環境與監控實作;應用程式 CPU 指標又可能依 cgroup 統計。應同時讀取宿主機與目標 cgroup 的 CPU、I/O、memory PSI 和配額事件,並把執行緒歸屬到 cgroup。若主機負載很高但目標 cgroup 沒有壓力,擴充該服務可能沒有收益。
追問三:負載 48、CPU idle 72%,是否一定存在大量 D 狀態?
不一定。還可能是指標不同步、CPU 平均掩蓋單核心熱點、工作受 affinity 或 cgroup 配額限制,或負載剛從高點下降而指數平均尚未衰減。檢查目前 /proc/loadavg 的 runnable 數、vmstat r/b、每核心使用率、R/D 執行緒數與收集時間,才能確定組成。
追問四:為什麼 D 狀態行程有時連 kill -9 都不消失?
不可中斷睡眠的設計目標,是讓某些核心操作在關鍵階段不被一般訊號中斷。SIGKILL 可以被標記為待處理,但工作通常要先從等待返回,排程到能處理退出的路徑,行程才會消失。修復裝置、掛載、網路或驅動程式等待,往往比重複發送訊號更重要;必要的主機重新啟動應依資料完整性與服務冗餘評估。
追問五:如何為 Load Average 設定告警?
不要複製固定的「負載大於 CPU 數」門檻。CPU 型服務應組合 load、可執行佇列、CPU PSI、使用率與 cgroup throttling;I/O 型服務應關注 I/O PSI、D 狀態、裝置或遠端儲存延遲與業務 SLO。告警門檻來自正常基線、持續時間、擴充速度與使用者影響,而且要標註指標範圍。