維命令實(shí)戰(zhàn):從系統(tǒng)排查到故障定位的完整指南)
1. 從一臺卡住的服務(wù)器說起為什么命令行的基本功比想象中重要很多人第一次接觸Linux都是從圖形界面開始的。點(diǎn)點(diǎn)鼠標(biāo)、拖拖文件感覺和用普通電腦沒什么兩樣。但真正到了生產(chǎn)環(huán)境尤其是遠(yuǎn)程連上一臺沒有桌面環(huán)境的服務(wù)器時你會發(fā)現(xiàn)手里能用的只有一行黑底白字的終端。這時候命令行的熟練程度直接決定了你解決問題的速度。我見過不少剛?cè)胄械呐笥延龅椒?wù)器響應(yīng)慢、磁盤滿了、進(jìn)程殺不掉這類問題第一反應(yīng)是重啟。重啟確實(shí)能解決一部分問題但它掩蓋了根因下次還會再犯。而真正能定位問題的往往是幾條看起來不起眼的命令——top、df、iostat、ss、journalctl。這些命令不需要你背下所有參數(shù)但你必須知道在什么場景下該用哪一個以及輸出結(jié)果里哪些數(shù)字是關(guān)鍵的。這篇內(nèi)容面向的是有一定Linux基礎(chǔ)、但還沒形成系統(tǒng)排查思路的讀者。我會按照信息探查→資源監(jiān)控→故障定位→恢復(fù)驗(yàn)證這條主線把日常運(yùn)維中最常用的命令串起來講。每個命令我都會說明它解決什么問題、輸出怎么看、有哪些容易踩的坑。你不需要死記硬背跟著場景走一遍自然就記住了。提示本文所有命令均在主流發(fā)行版如Debian系和RHEL系上驗(yàn)證過部分命令在不同發(fā)行版中參數(shù)略有差異我會在涉及的地方特別標(biāo)注。2. 系統(tǒng)信息探查先搞清楚自己在什么環(huán)境里在動手排查任何問題之前你得先知道這臺機(jī)器是什么系統(tǒng)、什么內(nèi)核、裝了哪些工具。這就像醫(yī)生看病要先問診一樣不了解環(huán)境就亂敲命令很容易得出錯誤結(jié)論。2.1 發(fā)行版與內(nèi)核版本一切判斷的起點(diǎn)最基礎(chǔ)的三條命令是uname -a、cat /etc/os-release和hostnamectl。uname -a輸出內(nèi)核版本、主機(jī)名、架構(gòu)等信息其中內(nèi)核版本決定了你能用哪些新特性。比如cgroup v2需要較新的內(nèi)核如果你在排查容器資源限制問題第一步就是確認(rèn)內(nèi)核版本。uname -a # 輸出示例Linux web-node-01 5.15.0-91-generic #101-Ubuntu SMP ... x86_64 GNU/Linuxcat /etc/os-release則告訴你發(fā)行版名稱和版本號。這個信息很關(guān)鍵因?yàn)椴煌l(fā)行版的包管理命令、服務(wù)管理方式、默認(rèn)配置文件路徑都不一樣。我遇到過有人在CentOS上找apt命令找了半天沒找到其實(shí)就是發(fā)行版搞混了。cat /etc/os-release # 輸出示例NAMEUbuntu VERSION22.04.3 LTS ...hostnamectl是systemd體系下的命令一條就能同時看到主機(jī)名、操作系統(tǒng)、內(nèi)核、架構(gòu)、虛擬化類型。虛擬化類型這一項(xiàng)特別有用——如果顯示KVM或VMware說明是虛擬機(jī)顯示docker或lxc說明你在容器里。容器里很多命令的行為和物理機(jī)不同比如free看到的內(nèi)存是宿主的還是容器的需要特別注意。2.2 硬件資源速查CPU、內(nèi)存、磁盤一眼看清lscpu比cat /proc/cpuinfo可讀性好得多它會匯總顯示CPU架構(gòu)、核心數(shù)、線程數(shù)、主頻、緩存大小。重點(diǎn)關(guān)注CPU(s)和Thread(s) per core這兩個數(shù)字相乘才是邏輯CPU總數(shù)。很多性能調(diào)優(yōu)參數(shù)比如Nginx的worker_processes都依賴這個數(shù)字。lscpu | grep -E ^(CPU\(s\)|Thread|Core|Socket|Model name)內(nèi)存方面free -h是最常用的。但要注意Linux的內(nèi)存管理邏輯是空閑內(nèi)存不用白不用所以free列顯示很小是正常的真正要關(guān)注的是available列。如果available持續(xù)低于總內(nèi)存的10%才說明內(nèi)存緊張。free -h # 重點(diǎn)關(guān)注 available 列而不是 free 列磁盤信息用lsblk和df -h配合看。lsblk展示塊設(shè)備的樹狀結(jié)構(gòu)能看出磁盤分區(qū)和掛載點(diǎn)的對應(yīng)關(guān)系df -h則顯示每個掛載點(diǎn)的使用率。這里有個常見誤區(qū)df看到的使用率和du統(tǒng)計出來的不一致。原因通常是文件被刪除但進(jìn)程還在持有句柄空間沒有真正釋放。這種情況用lsof | grep deleted就能找到元兇。2.3 網(wǎng)絡(luò)配置與連通性別急著ping先看鏈路網(wǎng)絡(luò)排查的第一步不是ping而是ip addr和ip route。ip addr看本機(jī)網(wǎng)卡和IP地址ip route看路由表。如果路由表里沒有默認(rèn)網(wǎng)關(guān)那ping任何外網(wǎng)地址都不會通這時候去查DNS是白費(fèi)功夫。ip addr show ip route show # 確認(rèn)默認(rèn)路由是否存在default via 192.168.1.1 dev eth0確認(rèn)鏈路層沒問題后再用ping測試連通性。但要注意很多云服務(wù)器默認(rèn)禁ping所以ping不通不代表網(wǎng)絡(luò)有問題。更可靠的測試是curl -I或nc -zv指定端口。比如測試到某臺服務(wù)器的SSH端口是否可達(dá)nc -zv 192.168.1.100 22 # 輸出Connection to 192.168.1.100 22 port [tcp/ssh] succeeded!DNS解析問題用dig或nslookup排查。dig short example.com直接返回解析結(jié)果干凈利落。如果解析慢可以用dig trace看整個解析鏈路卡在哪一步。注意ip命令屬于iproute2包老系統(tǒng)上可能只有ifconfig和route。建議盡早熟悉ip系列命令因?yàn)閚et-tools已經(jīng)停止維護(hù)多年了。3. 資源監(jiān)控與性能基線知道正常長什么樣才能發(fā)現(xiàn)不正常排查故障最大的難點(diǎn)不是修復(fù)而是判斷哪里不對。如果你不知道系統(tǒng)正常時的指標(biāo)范圍看到任何數(shù)字都會覺得可疑。所以建立性能基線是運(yùn)維的基本功。3.1 CPU使用率別被100%嚇到top是最經(jīng)典的實(shí)時監(jiān)控工具但它的輸出信息量很大新手容易看花眼。我建議重點(diǎn)關(guān)注這幾行l(wèi)oad average、%Cpu(s)、以及按P排序后的進(jìn)程列表。load average的三個數(shù)字分別代表1分鐘、5分鐘、15分鐘的平均負(fù)載。判斷負(fù)載是否過高要和邏輯CPU數(shù)量對比。比如4核CPU負(fù)載持續(xù)在4以上就說明有壓力了。但負(fù)載高不一定是CPU忙也可能是IO等待。這時候要看%Cpu(s)行里的waIO等待百分比。如果wa很高而us用戶態(tài)不高說明瓶頸在磁盤IO不在CPU。top -bn1 | head -20 # -b 批處理模式-n1 只刷新一次適合腳本采集htop是top的增強(qiáng)版支持彩色顯示、鼠標(biāo)操作、樹狀進(jìn)程視圖。如果系統(tǒng)里沒裝用包管理器裝一下就行。但生產(chǎn)環(huán)境不一定允許你隨便裝軟件所以top的基本功還是要扎實(shí)。3.2 內(nèi)存與交換分區(qū)OOM的前兆信號內(nèi)存問題最危險的是OOMOut Of Memory。Linux在內(nèi)存不足時會觸發(fā)OOM Killer隨機(jī)殺掉一個進(jìn)程來釋放內(nèi)存。被殺的往往是占用內(nèi)存最大的進(jìn)程可能是你的數(shù)據(jù)庫或應(yīng)用服務(wù)。監(jiān)控內(nèi)存除了free -h還要看/proc/meminfo里的Committed_AS和CommitLimit。如果Committed_AS接近CommitLimit說明系統(tǒng)已經(jīng)過度承諾內(nèi)存隨時可能觸發(fā)OOM。grep -E CommitLimit|Committed_AS /proc/meminfo交換分區(qū)swap的使用情況也值得關(guān)注。vmstat 1輸出的si和so列分別表示換入和換出速率。如果這兩個值持續(xù)非零說明物理內(nèi)存不夠系統(tǒng)在頻繁換頁性能會急劇下降。vmstat 1 5 # si/so 持續(xù)大于0說明內(nèi)存壓力大3.3 磁盤IO最容易被忽視的瓶頸磁盤IO問題往往表現(xiàn)為系統(tǒng)很卡但CPU不高。iostat -x 1是排查IO問題的利器重點(diǎn)關(guān)注%util和await兩列。%util接近100%說明磁盤飽和await是平均等待時間毫秒機(jī)械硬盤超過20ms、SSD超過5ms就值得警惕了。iostat -x 1 3 # 關(guān)注 %util 和 await以及 r/s、w/s 判斷是讀多還是寫多iotop能按進(jìn)程顯示IO占用但需要root權(quán)限且內(nèi)核開啟CONFIG_TASK_IO_ACCOUNTING。如果iotop不可用可以用pidstat -d 1替代它按進(jìn)程統(tǒng)計讀寫速率。pidstat -d 1 5 # 輸出每個進(jìn)程的 kB_rd/s 和 kB_wr/s3.4 網(wǎng)絡(luò)流量帶寬跑滿了嗎網(wǎng)絡(luò)監(jiān)控用sar -n DEV 1或iftop。sar是sysstat包的一部分能看歷史數(shù)據(jù)適合事后分析。iftop實(shí)時顯示各連接的帶寬占用適合定位誰在偷跑流量。sar -n DEV 1 5 # 關(guān)注 rxkB/s 和 txkB/s對比網(wǎng)卡標(biāo)稱帶寬如果發(fā)現(xiàn)帶寬跑滿下一步是用ss -tunp看具體是哪些連接在傳輸。ss比netstat快得多在連接數(shù)多的時候優(yōu)勢明顯。ss -tunp | head -30 # -t TCP, -u UDP, -n 不解析服務(wù)名, -p 顯示進(jìn)程提示建立基線的方法很簡單——在系統(tǒng)正常運(yùn)行時每隔一段時間采集一次上述指標(biāo)記錄在表格里。堅(jiān)持一兩周你就能看出哪些波動是正常的哪些是異常的。4. 故障定位實(shí)戰(zhàn)從現(xiàn)象到根因的排查鏈路前面講的是看什么這一章講怎么想。故障排查最忌諱東一榔頭西一棒子必須有清晰的排查鏈路。我通常按照現(xiàn)象確認(rèn)→范圍縮小→根因定位→驗(yàn)證修復(fù)四步走。4.1 服務(wù)不可用先確認(rèn)是進(jìn)程問題還是網(wǎng)絡(luò)問題假設(shè)用戶反饋網(wǎng)站打不開。第一步不是重啟服務(wù)而是確認(rèn)服務(wù)進(jìn)程是否還在。systemctl status nginx # 或者用 ps 檢查 ps aux | grep nginx | grep -v grep如果進(jìn)程在但服務(wù)不可用下一步檢查端口監(jiān)聽狀態(tài)ss -tlnp | grep :80 # 確認(rèn)是否有進(jìn)程監(jiān)聽80端口如果端口沒監(jiān)聽說明服務(wù)啟動失敗或配置有問題。這時候看日志journalctl -u nginx --since 10 minutes ago # 或者看應(yīng)用自己的日志文件 tail -100 /var/log/nginx/error.log如果端口在監(jiān)聽但外部訪問不了問題可能出在防火墻或安全組。檢查本機(jī)防火墻規(guī)則iptables -L -n # 或者 firewalld firewall-cmd --list-all這里有個經(jīng)驗(yàn)云服務(wù)器的安全組規(guī)則和本機(jī)防火墻是兩層獨(dú)立的過濾任何一層沒放行都會導(dǎo)致訪問失敗。排查時兩層都要看。4.2 系統(tǒng)響應(yīng)慢用排除法鎖定資源瓶頸系統(tǒng)變慢的原因無非四種CPU忙、內(nèi)存不足、磁盤IO高、網(wǎng)絡(luò)擁塞。用vmstat 1可以快速排除vmstat 1 5 # r 列等待運(yùn)行的進(jìn)程數(shù)持續(xù)大于CPU核數(shù)說明CPU不夠 # si/so換頁速率非零說明內(nèi)存不足 # waIO等待高說明磁盤慢根據(jù)vmstat的輸出基本能判斷瓶頸方向。如果是CPU問題用top找占用最高的進(jìn)程如果是內(nèi)存問題用ps aux --sort-%mem | head找內(nèi)存大戶如果是IO問題用iostat -x和pidstat -d定位具體磁盤和進(jìn)程。ps aux --sort-%mem | head -10 ps aux --sort-%cpu | head -104.3 磁盤空間告急df和du不一致怎么辦df -h顯示磁盤滿了但du -sh /*統(tǒng)計出來卻小很多。這是運(yùn)維中最經(jīng)典的幽靈空間問題。原因是某個大文件被刪除了但仍有進(jìn)程持有它的文件句柄內(nèi)核不會釋放這部分空間。定位方法lsof | grep deleted | head -20 # 找到持有已刪除文件的進(jìn)程PID解決辦法是重啟該進(jìn)程或者用 /proc/PID/fd/FD清空文件內(nèi)容不推薦可能導(dǎo)致進(jìn)程異常。最穩(wěn)妥的還是重啟進(jìn)程。另一個常見原因是inode耗盡。df -i查看inode使用率如果100%了即使空間還有剩余也無法創(chuàng)建新文件。這種情況通常是大量小文件導(dǎo)致的比如緩存目錄、郵件隊(duì)列、session文件。清理這些目錄即可。df -i # 找到inode使用率高的掛載點(diǎn)然后統(tǒng)計該目錄下文件數(shù)量 find /var/spool -type f | wc -l4.4 進(jìn)程殺不掉僵尸進(jìn)程與不可中斷睡眠kill -9都?xì)⒉坏舻倪M(jìn)程通常處于D狀態(tài)不可中斷睡眠一般是在等待IO完成。這時候看進(jìn)程的wchan內(nèi)核等待通道ps -eo pid,stat,wchan,cmd | grep D cat /proc/PID/stack如果確認(rèn)是IO問題需要先解決底層存儲的故障進(jìn)程才會恢復(fù)。強(qiáng)行殺D狀態(tài)進(jìn)程是無效的因?yàn)樗豁憫?yīng)信號。僵尸進(jìn)程Z狀態(tài)則是另一種情況。僵尸進(jìn)程本身不占資源但會占用進(jìn)程表項(xiàng)。如果大量僵尸進(jìn)程堆積說明父進(jìn)程沒有正確回收子進(jìn)程。解決辦法是找到父進(jìn)程并重啟它。ps -eo pid,ppid,stat,cmd | awk $3 ~ /Z/ # 找到僵尸進(jìn)程的PPID然后處理父進(jìn)程4.5 網(wǎng)絡(luò)連接異常從socket狀態(tài)入手ss -s能快速匯總當(dāng)前socket狀態(tài)如果TIME_WAIT數(shù)量異常大說明短連接過多可能需要調(diào)整內(nèi)核參數(shù)或改用長連接。ss -s # 輸出各狀態(tài)連接數(shù)統(tǒng)計TIME_WAIT過多的調(diào)優(yōu)參數(shù)# 查看當(dāng)前值 sysctl net.ipv4.tcp_tw_reuse sysctl net.ipv4.tcp_max_tw_buckets # 臨時調(diào)整 sysctl -w net.ipv4.tcp_tw_reuse1但要注意tcp_tw_reuse只對客戶端有效服務(wù)端大量TIME_WAIT應(yīng)該從應(yīng)用層優(yōu)化比如使用連接池。如果連接被拒絕Connection refused說明目標(biāo)端口沒有監(jiān)聽如果是超時Connection timed out說明網(wǎng)絡(luò)不通或被防火墻攔截。用traceroute或mtr可以看鏈路在哪一跳斷了。mtr -r -c 10 192.168.1.100 # 報告模式發(fā)送10個包顯示每跳丟包率5. 日志分析與事后復(fù)盤讓每一次故障都變成經(jīng)驗(yàn)故障解決后如果不做復(fù)盤下次遇到類似問題還是要從頭查起。日志是最寶貴的線索來源但前提是你會用工具高效地檢索和分析。5.1 journalctlsystemd體系的日志中樞現(xiàn)代Linux發(fā)行版基本都用systemd管理服務(wù)journalctl就是查看日志的統(tǒng)一入口。常用組合# 查看指定服務(wù)的日志 journalctl -u nginx --since today # 按時間范圍過濾 journalctl --since 2024-01-01 10:00:00 --until 2024-01-01 11:00:00 # 只看錯誤級別 journalctl -p err -b # 實(shí)時跟蹤 journalctl -f -u nginx-b參數(shù)表示只看本次啟動以來的日志排查重啟后的問題特別有用。-p按優(yōu)先級過濾err及以上級別才會顯示。如果日志量很大可以配合grep做二次過濾journalctl -u nginx --since 1 hour ago | grep -i error\|fail\|timeout5.2 傳統(tǒng)日志文件tail、grep、awk的組合拳不是所有服務(wù)都走journald很多應(yīng)用還是寫自己的日志文件。tail -f實(shí)時跟蹤是最基本的操作但面對大文件直接grep可能很慢。這時候可以用awk按時間范圍過濾awk /2024-01-01 10:00/,/2024-01-01 11:00/ /var/log/app.log統(tǒng)計錯誤出現(xiàn)次數(shù)grep -c ERROR /var/log/app.log按錯誤類型分組統(tǒng)計grep ERROR /var/log/app.log | awk {print $5} | sort | uniq -c | sort -rn | head這個組合能快速告訴你哪類錯誤最多優(yōu)先解決高頻問題。5.3 日志輪轉(zhuǎn)與磁盤保護(hù)日志寫滿磁盤是新手常踩的坑。logrotate是標(biāo)準(zhǔn)的日志輪轉(zhuǎn)工具配置文件在/etc/logrotate.d/下。檢查某個服務(wù)的輪轉(zhuǎn)配置cat /etc/logrotate.d/nginx關(guān)鍵參數(shù)daily每天輪轉(zhuǎn)、rotate 7保留7份、compress壓縮舊日志、size 100M超過100M就輪轉(zhuǎn)。如果日志增長太快可以調(diào)小size或增加輪轉(zhuǎn)頻率。手動觸發(fā)輪轉(zhuǎn)測試logrotate -d /etc/logrotate.d/nginx # -d 調(diào)試模式只顯示會做什么不實(shí)際執(zhí)行注意修改logrotate配置后最好用-d先驗(yàn)證一遍確認(rèn)無誤再實(shí)際執(zhí)行。我曾經(jīng)因?yàn)榕渲美锷倭藗€空格導(dǎo)致日志被輪轉(zhuǎn)后沒有創(chuàng)建新文件服務(wù)直接寫不進(jìn)去了。6. 幾條容易被忽略但關(guān)鍵時刻能救命的命令前面講的都是系統(tǒng)性的排查方法最后分享幾條偏方級別的命令平時用不到但特定場景下能省很多時間。6.1 用strace跟蹤系統(tǒng)調(diào)用當(dāng)某個進(jìn)程行為異常但日志里沒有有用信息時strace能直接看它調(diào)用了哪些系統(tǒng)調(diào)用、卡在哪一步。strace -p PID -f -e tracenetwork # 跟蹤指定進(jìn)程的網(wǎng)絡(luò)相關(guān)系統(tǒng)調(diào)用-f表示跟蹤子進(jìn)程-e trace可以過濾特定類型的調(diào)用。比如排查連接超時就跟蹤network排查文件問題就跟蹤file。但要注意strace會顯著降低進(jìn)程性能生產(chǎn)環(huán)境慎用最好只在測試環(huán)境或問題復(fù)現(xiàn)時短時間使用。6.2 用lsof找回被刪除的文件前面提到lsof | grep deleted能找到被刪除但未釋放的文件。如果這個文件很重要還能通過/proc/PID/fd/FD路徑把它復(fù)制出來cp /proc/1234/fd/5 /tmp/recovered_file前提是文件句柄還在進(jìn)程還沒重啟。這個技巧在誤刪配置文件時特別有用。6.3 用dmesg看內(nèi)核消息有些問題日志里看不到但內(nèi)核已經(jīng)記錄了。比如OOM Killer殺進(jìn)程、磁盤IO錯誤、網(wǎng)卡丟包都會在dmesg里留下痕跡。dmesg -T | tail -50 # -T 顯示可讀時間戳如果看到Out of memory: Killed process說明發(fā)生了OOM看到I/O error說明磁盤有硬件問題。這些信息對定位根因至關(guān)重要。6.4 用nc和curl做快速連通性測試nc -zv host port測試TCP端口連通性curl -I測試HTTP服務(wù)可用性curl -w輸出詳細(xì)的請求耗時分解curl -o /dev/null -s -w DNS: %{time_namelookup}s\nConnect: %{time_connect}s\nTTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n http://example.com這個輸出能幫你判斷慢在DNS解析、TCP連接還是服務(wù)端處理。如果time_namelookup很長說明DNS有問題如果time_connect很長說明網(wǎng)絡(luò)延遲高如果time_starttransfer很長說明服務(wù)端處理慢。7. 把命令變成肌肉記憶我的日常練習(xí)方法說了這么多命令最后聊聊怎么真正掌握它們。我的經(jīng)驗(yàn)是不要試圖一次記住所有參數(shù)而是圍繞場景反復(fù)練習(xí)。比如這周專門練磁盤排查遇到任何磁盤相關(guān)問題都強(qiáng)迫自己用df、du、lsof、iostat這套組合去分析練到不用查文檔就能敲出來為止。另一個方法是給自己出題。比如故意用dd命令把某個分區(qū)寫滿然后練習(xí)定位和清理或者用stress工具制造CPU和內(nèi)存壓力練習(xí)用top、vmstat、pidstat定位瓶頸。這種自導(dǎo)自演的故障演練比看十篇文章都管用。還有一點(diǎn)很重要養(yǎng)成記錄的習(xí)慣。每次排查完一個故障把現(xiàn)象、排查過程、根因、解決方案記下來。積累多了你會發(fā)現(xiàn)很多問題其實(shí)是同一類排查思路可以復(fù)用。我自己的筆記里就有一個故障模式庫按現(xiàn)象分類比如服務(wù)無響應(yīng)、磁盤滿、CPU高、網(wǎng)絡(luò)慢每個模式下列出可能的原因和對應(yīng)的排查命令。遇到新問題先查庫能省很多時間。提示如果你在云環(huán)境里練習(xí)注意不要在生產(chǎn)實(shí)例上做破壞性操作。可以開一臺按量付費(fèi)的測試機(jī)用完就釋放成本很低。Linux命令行的學(xué)習(xí)曲線確實(shí)有點(diǎn)陡但一旦跨過那個坎你會發(fā)現(xiàn)它是最自由、最高效的操作方式。圖形界面能做的事命令行都能做圖形界面做不了的事命令行也能做。而且命令行的輸出是文本可以管道、可以重定向、可以腳本化這是圖形界面永遠(yuǎn)比不了的。希望這篇內(nèi)容能幫你建立起自己的排查思路下次遇到問題時不再慌張而是有條不紊地一步步逼近根因。