問:如果一個大型項目,某一個時間所有的CPU的 已經被占用了,導致服務不可用,我們開發人員 應該如何使服務器盡快恢復正常
答:應對CPU 100%導致服務不可用的緊急恢復流程
面試官,如果遇到這種情況,我會立即按照以下步驟操作,目標是盡快恢復服務,而不是立即深入排查復雜原因。
第一步:保持冷靜,快速止損(首要目標:恢復服務)
擴容/重啟:這是最快、最有效的止損方案。
水平擴容:如果云環境,立即申請新的服務器實例,加入集群,將流量切到新節點。這是首選,對用戶影響最小。
重啟大法:如果無法快速擴容,果斷選擇分批重啟應用服務器。先重啟一小部分(如20%),驗證服務恢復后,再逐步重啟其他節點。重啟可以立即釋放資源,清除可能的內存泄漏或死循環等問題。
服務降級/限流:
降級:立即確認是否有非核心功能(如排行榜、推薦系統、報表生成)可以緊急降級,直接關閉其服務以節省CPU資源。
限流/熔斷:在網關或API層立即配置嚴格限流,拒絕大部分非關鍵請求,只保障核心業務(如下單、支付)的少量請求能通過,防止整個系統被拖垮。
第二步:定位問題根因(并行于止損操作)
在重啟/擴容的同時,必須立刻抓取現場信息,以便后續分析,避免問題復發。
快速登錄服務器,使用標準命令行工具鏈定位問題進程和線程:
top -c
:查看整體CPU使用情況,找到最耗CPU的進程ID(PID)。top -Hp [PID]
:查看該進程中最耗CPU的線程ID(TID)。printf "%x\n" [TID]
:將TID轉換為十六進制,便于在日志中搜索。
抓取線程快照(Thread Dump/JStack):
jstack [PID] > jstack.log
:立即抓取Java應用的線程棧信息。重點分析之前找到的高CPU線程的十六進制ID,查看它正在執行什么代碼(通常是處于
RUNNABLE
狀態,卡在某個方法循環、計算或IO等待)。
輔助信息收集:
vmstat 1
?/?mpstat 1
:查看CPU使用分布(用戶態、內核態、IO等待)。jstat -gcutil [PID] 1s
:查看GC情況,判斷是否因頻繁FULL GC導致。查看監控系統:如Prometheus/Grafana,觀察問題發生時間點的QPS、響應時間、緩存命中率、數據庫連接數等指標的變化,尋找關聯性。
第三步:分析并修復根因
根據第二步收集的信息,常見原因和應對策略如下:
可能原因 | 分析線索 | 解決方案 |
---|---|---|
1. 死循環/無限遞歸 | Thread Dump中某線程長期RUNNABLE 且執行相同方法。 | 修復代碼邏輯,增加循環邊界或終止條件。 |
2. 頻繁GC(特別是FULL GC) | jstat 顯示老年代幾乎占滿,GC時間飆升。 | 緊急重啟;長期需分析內存泄漏、優化JVM參數。 |
3. 序列化/反序列化問題 | 線程棧出現在ObjectInputStream 等相關方法。 | 回滾相關代碼或檢查輸入數據是否異常。 |
4. 鎖競爭激烈 | 線程棧中出現大量BLOCKED 狀態的線程,等待同一鎖。 | 優化鎖粒度、改用并發類、避免長時間持鎖。 |
5. 算法復雜度爆炸 | 因某個特定請求,觸發了高復雜度(如O(n2))的計算。 | 限流、優化算法、增加緩存。 |
6. 外部依賴變慢 | 線程棧大量卡在數據庫/網絡IO調用,監控顯示依賴方超時。 | 快速熔斷該依賴, fallback降級,避免被拖垮。 |
第四步:復盤與長期優化
復盤:事后必須組織復盤,寫出事故報告(Post-mortem),明確根本原因、處理過程、改進措施。
建設監控告警:
設置CPU使用率、GC頻率、接口響應時間、錯誤率等閾值告警,做到提前發現,而非事后補救。
常態化措施:
壓測:定期進行壓力測試,了解系統瓶頸和容量上限。
限流降級:在代碼和架構中預先埋好降級開關和限流策略。
可觀測性:完善鏈路追蹤(APM)、日志系統,保證下次能更快定位問題。
總結給面試官
“面對這種情況,我的首要原則是快速止損,恢復服務。會立即采取擴容或分批重啟的策略,同時并行進行服務降級和限流以保障核心業務。
在恢復過程中,我會第一時間抓取現場信息(如top
、jstack
),定位消耗CPU的元兇,是死循環、GC問題還是外部依賴導致。
服務恢復后,我會立即組織復盤,從根本上解決問題,并通過完善監控告警、壓測和熔斷降級機制,防止未來再次發生同類事故。”