前言:從“玄學”到“科學”
“服務又卡了!”
這是我們每個Linux運維/SRE工程師最不想聽到,卻又最常聽到的一句話。隨之而來的,往往是開發、產品、甚至老板的連環追問。此時,一個經驗不足的工程師可能會立刻登錄服務器,top
、free
、df
三板斧輪番上陣,然后憑感覺猜測:“是不是CPU滿了?”、“內存不夠了吧?”、“磁盤IO太高?”
這種“猜謎式”的排錯方式,在簡單的場景下或許能僥幸成功,但面對復雜的生產環境,無異于蒙眼走鋼絲。真正的專業運維,應該像一名經驗豐富的醫生,通過“望、聞、問、切”,遵循一套科學、系統的方法論,層層遞進,直達病灶。
本文將分享我多年來沉淀的一套Linux性能問題排查框架。它從經典的 USE (Utilization, Saturation, Errors) 方法 和 Google SRE 的 “四大黃金指標” 汲取靈感,旨在將性能問題從一門“玄學”,轉變為一門有據可查、有路可循的“科學”。
第一章:排錯心法——建立正確的思維模型
在敲下任何命令之前,請先在腦海中建立這個模型。我們排查任何性能問題,本質上都是在分析系統資源的瓶頸。對于一臺服務器而言,核心資源無外乎四種:
- CPU:計算能力的核心。它是否被占滿?是否在等待其他資源?
- 內存 (Memory):數據和程序的載體。是否足夠?是否存在泄漏?是否因為內存不足導致頻繁與慢速磁盤交換(Swap)?
- 存儲I/O (Storage I/O):數據的讀寫通道。磁盤是否已經不堪重負?響應是否過慢?
- 網絡I/O (Network I/O):與外部世界溝通的橋梁。帶寬是否耗盡?是否存在大量的連接錯誤或重傳?
我們的所有工作,都將圍繞這四大資源展開。排查的順序通常是從全局到局部,從系統到應用。
第二章:第一現場——1分鐘快速“望聞問切”
收到告警或報告后,第一時間登錄服務器,我們需要在最短時間內對系統健康狀況有一個整體評估。這幾條命令是你的黃金“30秒”。
1. uptime
- 系統負載(Load Average)
$ uptime15:30:10 up 52 days, 4:11, 1 user, load average: 8.50, 5.30, 2.10
load average
的三個數值分別代表過去1分鐘、5分鐘、15分鐘的平均負載。它衡量的是正在運行和**等待運行(等待CPU或等待I/O)**的進程總數。
解讀關鍵:
- 核心數對比: 如果你的服務器是8核,那么負載在8以下通常是安全的。如果負載持續高于核心數(比如這里的1分鐘負載8.50),說明系統已經出現擁堵,任務需要排隊等待處理。
- 趨勢判斷: 觀察三個數值的趨勢。
8.50, 5.30, 2.10
:負載在急劇上升,問題可能剛剛發生或正在惡化。2.10, 5.30, 8.50
:負載在逐漸下降,問題可能已經緩解,但需要調查原因。
2. dmesg -T
- 內核的吶喊
內核日志是發現硬件錯誤、OOM (Out of Memory) Killer事件等底層問題的關鍵。
$ dmesg -T | tail
[Fri Sep 5 15:25:01 2025] oom-kill:constraint=CONSTRAINT_NONE,nodemask=(null),cpuset=/,mems_allowed=0,global_oom,task_memcg=/user.slice,task=java,pid=12345,uid=1000
[Fri Sep 5 15:25:01 2025] Out of memory: Killed process 12345 (java) total-vm:12345678kB, anon-rss:8765432kB, file-rss:0kB, shmem-rss:0kB
看到 Out of memory
或 I/O error
等字樣,你就可能直接找到了問題的根源。
3. vmstat 1
- 動態的系統快照
vmstat
是一個強大的工具,vmstat 1
會每秒輸出一次系統各項指標的動態變化。
$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----r b swpd free buff cache si so bi bo in cs us sy id wa st2 1 0 1.2G 150M 10.2G 0 0 2 25 115 312 5 2 93 0 0
10 0 0 1.1G 150M 10.2G 0 0 8510 150K 45K 98K 35 15 10 40 09 0 0 1.0G 150M 10.2G 0 0 9230 120K 51K 110K 33 18 5 44 0
關注重點列:
procs
->r
(Runnable): 正在運行和等待CPU的進程數。如果這個值持續大于CPU核心數,說明CPU存在瓶頸。procs
->b
(Blocked): 等待I/O的進程數。如果這個值不為0且持續存在,說明I/O可能有問題。swap
->si
,so
(Swap In/Out): 如果這兩個值長期大于0,說明系統正在使用Swap,物理內存嚴重不足,性能會急劇下降。cpu
->us
(User): 用戶態CPU占用。高的話說明是應用程序消耗了大量CPU。cpu
->sy
(System): 內核態CPU占用。高的話可能是系統調用頻繁或內核模塊有問題。cpu
->id
(Idle): 空閑CPU。cpu
->wa
(Wait): 等待I/O的CPU時間百分比。這個值高,直接表明瓶頸在磁盤I/O。
通過這三個命令,我們已經對系統的CPU、內存、I/O狀況有了初步的判斷。接下來,就是針對性的深入分析。
第三章:庖丁解牛——四大資源的深度剖析
3.1 CPU 瓶頸分析
當 uptime
負載高,vmstat
的 r
列值大,us
或 sy
CPU占用率高時,我們聚焦CPU。
-
top
/htop
:top
是傳統工具,按P
按CPU排序,按M
按內存排序。htop
是top
的增強版,界面更友好,信息更豐富。- 目標: 快速找到是哪個進程(PID) 消耗了最多的CPU。
-
pidstat -u 1
:
pidstat
可以更細致地觀察進程的CPU使用情況,區分用戶態(%usr
)和內核態(%system
)。 -
perf
:終極武器
如果發現是某個進程CPU高,但想知道是進程中的哪個函數導致的問題,perf
就派上用場了。# 記錄指定進程(PID)的CPU事件,持續60秒 $ perf record -F 99 -p <PID> -g -- sleep 60# 分析記錄的數據,生成報告 $ perf report
perf report
會給出一個詳細的函數調用棧和CPU消耗占比,是定位代碼級別性能問題的神器。
3.2 內存瓶頸分析
當 vmstat
的 si/so
頻繁發生,或者 dmesg
出現OOM Killer時,問題在內存。
-
free -h
:$ free -htotal used free shared buff/cache available Mem: 15G 3.5G 1.2G 150M 11G 11.5G Swap: 2.0G 0B 2.0G
重要理念: Linux中
free
的內存少不一定是壞事!buff/cache
是內核為了提升性能而使用的緩存,在需要時可以被回收。真正需要關注的是available
,它代表應用程序可用的內存。如果available
很小,同時Swap開始被使用,那才是真正的內存壓力。 -
ps aux --sort=-%mem | head -n 10
:
快速找出最耗費內存的進程。 -
smem
:更精確的內存報告
smem
可以提供更精準的內存使用報告,特別是對于PSS(Proportional Set Size)的計算,能更真實地反映共享庫情況下的內存占用。 -
內存泄漏排查:
這是一個復雜的話題,通常需要借助valgrind
,gdb
等工具,或者針對特定語言的內存分析器(如JVM的jmap
,jhat
)。運維層面能做的是通過監控,觀察特定進程的內存使用是否隨時間只增不減,從而定位可疑進程,交由開發處理。
3.3 存儲 I/O 瓶頸分析
當 uptime
負載高,但 vmstat
中 wa
CPU占用率高時,瓶頸在I/O。
-
iostat -dx 1
:
這是診斷磁盤I/O問題的核心工具。$ iostat -dx 1 Device r/s w/s rkB/s wkB/s await %util sda 500.00 300.00 4000.00 6000.00 25.50 98.00
關注指標:
r/s
,w/s
: 每秒讀/寫次數 (IOPS)。rkB/s
,wkB/s
: 每秒讀/寫數據量 (吞吐量)。await
: 每個I/O請求的平均處理時間(包括排隊時間),單位是毫秒。這是非常關鍵的指標。對于SSD,await
通常應在1ms以下;對于HDD,幾毫秒到十幾毫秒。如果這個值持續很高(如幾十甚至上百ms),說明磁盤響應非常慢。%util
: 磁盤I/O的繁忙程度。如果接近100%,說明磁盤已經飽和。
-
iotop
:
類似top
,但用于顯示磁盤I/O。可以清晰地看到是哪個進程在瘋狂讀寫磁盤。
3.4 網絡 I/O 瓶頸分析
網絡問題通常表現為應用訪問慢、超時、丟包等。
-
ss -tunap
:
ss
是netstat
的現代替代品,速度更快。這條命令可以列出所有TCP/UDP連接及其狀態。
關注重點:- 大量的
CLOSE_WAIT
狀態:通常是應用程序代碼有Bug,沒有正確關閉連接。 - 大量的
TIME_WAIT
狀態:在高并發短連接場景下正常,但如果過多可能耗盡端口資源。 - 查看
Recv-Q
和Send-Q
:如果不為0,可能表示數據收發隊列存在積壓。
- 大量的
-
iftop
/nload
:
實時監控網卡流量,可以直觀地看到哪個連接占用了最多的帶寬。 -
ping
,traceroute
,mtr
:
診斷網絡延遲和丟包的經典工具。mtr
是ping
和traceroute
的結合體,能持續探測并給出每一跳的延遲和丟包率,是診斷網絡鏈路問題的最佳工具。 -
防火墻和DNS:
不要忘記檢查iptables
/firewalld
規則是否復雜導致性能下降,以及/etc/resolv.conf
中的DNS服務器是否響應緩慢。
第四章:深入應用——從系統調用到應用日志
當系統層面指標看似正常,但應用依然緩慢時,我們需要深入到應用內部。
-
strace -p <PID>
:
跟蹤一個進程的系統調用。你可以看到它在讀寫什么文件,請求什么網絡連接。如果一個應用卡住,strace
可能會顯示它正阻塞在某個特定的系統調用上。 -
lsof -p <PID>
:
列出指定進程打開的所有文件和網絡連接。這對于排查“Too many open files”錯誤或查找文件句柄泄漏非常有用。 -
應用日志(The MOST IMPORTANT!):
/var/log
目錄下的應用日志(如nginx/access.log
,mysql/slow-query.log
)和journalctl
是信息金礦。應用自身的錯誤日志、慢查詢日志,往往直接就指明了問題的根源。
第五章:實戰演練——一個Web服務變慢的案例
- 現象: 用戶反饋網站打開非常慢。
- 第一現場:
uptime
顯示load average
很高 (例如: 20),遠超8核CPU。vmstat 1
顯示wa
長期在60%以上。 - 初步判斷: 典型的I/O瓶頸。CPU本身不忙,而是在等待磁盤。
- 深入I/O:
iostat -dx 1
顯示/dev/sdb
的%util
接近100%,await
高達200ms。 - 定位進程:
iotop
顯示一個mysqld
進程占用了幾乎所有的磁盤寫操作。 - 深入應用: 登錄MySQL,開啟慢查詢日志或查看
SHOW FULL PROCESSLIST;
,發現大量查詢卡在updating
狀態,并且涉及一個沒有索引的大表。 - 根源: 數據庫一個慢查詢(更新操作)鎖住了表,導致大量寫請求阻塞,最終拖垮了整個服務器的磁盤I/O。
- 解決: 聯系開發優化SQL,為相關字段添加索引。問題解決。
總結與展望:從救火英雄到系統架構師
我們通過一套系統化的方法,從宏觀的系統負載,到細分的四大資源(CPU、內存、I/O、網絡),再到微觀的應用內部調用和日志,最終定位并解決了問題。
然而,一個頂級的運維/SRE,其價值絕不僅僅是“救火”。排查故障只是被動的響應。更重要的是主動的預防。
- 監控與告警: 建立基于Prometheus + Grafana等現代監控體系,對我們上面提到的所有關鍵指標(Load, CPU Util, Memory Available, IO await, Network Retransmit 等)設置科學的閾值和告警。
- 容量規劃: 定期分析監控數據,預測資源增長趨勢,在瓶頸出現前進行擴容或優化。
- 自動化: 將重復的排查步驟、應急操作腳本化、自動化,縮短MTTR(平均修復時間)。
- 與開發協作(DevOps): 將運維的性能視角帶入開發和測試階段,從源頭上避免性能低劣的代碼被發布到生產環境。
技術的道路永無止境。工具會不斷迭代,從 top
到 perf
,從 Nagios
到 Prometheus
。但底層的方法論——數據驅動、邏輯推理、分層排查——是永恒不變的。希望這篇長文,能成為你工具箱里的一張清晰的地圖,在你面對下一次“服務又卡了”的挑戰時,能夠從容不迫,直抵核心。