故障排查實戰(zhàn):從CPU到網(wǎng)絡(luò)的全鏈路方法論)
1. 先搞清楚故障排查到底在排什么干了這么多年運維我見過太多同事在系統(tǒng)出問題時直接抄起鍵盤就開始一通操作看到CPU高就kill進程看到磁盤滿就rm文件折騰半天發(fā)現(xiàn)故障還在甚至把業(yè)務(wù)搞得更糟。問題出在哪出在缺少一套系統(tǒng)性的排查思路。Linux系統(tǒng)故障排查核心不在于你會用多少命令而在于你如何把“現(xiàn)象”還原成“鏈路”。一臺服務(wù)器從硬件到內(nèi)核再到文件系統(tǒng)、進程調(diào)度、網(wǎng)絡(luò)協(xié)議棧每一層都可能出問題而現(xiàn)象往往是最表面的一層。比如用戶反饋“網(wǎng)站打開很慢”可能的根因有幾十種CPU爭搶、磁盤I/O、網(wǎng)絡(luò)丟包、DNS解析慢、后端應(yīng)用線程阻塞、甚至是物理機鄰居搶占帶寬。如果沒有一套成體系的排查思路你就是在瞎猜。我傾向把排查思路拆成六個固定動作確認(rèn)現(xiàn)象、評估影響、收集信息、形成假設(shè)、驗證根因、修復(fù)復(fù)盤。這六步看起來簡單但每一步都有講究。確認(rèn)現(xiàn)象不是聽用戶說“卡了”就完事要量化到底什么指標(biāo)異常評估影響決定了你的處理優(yōu)先級——是保業(yè)務(wù)優(yōu)先還是定位根因優(yōu)先收集信息要求你在動手“修”之前先把現(xiàn)場保留下來否則進程一重啟、緩存一清空證據(jù)就沒了。這套方法論適合誰剛?cè)胄械倪\維新手、從開發(fā)轉(zhuǎn)到運維的工程師、以及想要標(biāo)準(zhǔn)化團隊故障處理流程的運維負責(zé)人。后面我會用實際案例把每一步掰開來講包括我這些年踩過的坑和總結(jié)出的經(jīng)驗。提示故障排查的第一原則是“先恢復(fù)后定位”。如果業(yè)務(wù)正在受損優(yōu)先通過重啟服務(wù)、切換流量、擴容節(jié)點等手段止損再慢慢分析根因。別為了?,F(xiàn)場而讓故障持續(xù)發(fā)酵。2. CPU與系統(tǒng)負載最容易被誤判的一類問題2.1 先看懂負載和CPU使用率的關(guān)系很多人一看到load average超過CPU核數(shù)就慌了認(rèn)定是CPU不夠用。這是個非常大的誤區(qū)。我做個類比CPU使用率是“正在干活的比例”而負載是“排隊等干活的人數(shù)”。想象一家銀行柜臺一個柜臺一個CPU核同時只能服務(wù)一個客戶使用率是說這個柜員有多忙而負載則統(tǒng)計著正在辦業(yè)務(wù)加上排隊等著的所有人。如果一個柜員同時在處理大量的事務(wù)但每個事務(wù)都在等磁盤返回數(shù)據(jù)也就是I/O等待他手上沒閑著可也沒在真正計算——這時候CPU使用率可能不高但負載飆升。所以排查的第一步永遠是先區(qū)分負載升高到底是CPU計算密集、I/O等待還是進程阻塞。實操上我會依次執(zhí)行三條命令uptime top vmstat 1 5uptime看過去1/5/15分鐘的負載趨勢判斷是突發(fā)還是持續(xù)。top看整體CPU占用分布重點看us用戶態(tài)、sy內(nèi)核態(tài)、waI/O等待和id空閑幾個值。vmstat 1 5每隔1秒采樣5次看r運行隊列、b阻塞進程數(shù)、wa、cs上下文切換這幾列。如果us高說明有進程在瘋狂消耗CPU下一步用top -Hp pid找到具體線程或者用pidstat -t -p pid 1觀察哪個線程占CPU。如果wa高而us低那問題在磁盤I/O別在CPU層面浪費時間直接跳到磁盤排查。如果r隊列長期大于CPU核數(shù)的數(shù)倍但us/sy并不高多半是進程在鎖等待或者內(nèi)核態(tài)出了問題。2.2 CPU排查的實戰(zhàn)路徑定位到CPU消耗大戶之后接下來要回答“它在干什么”。我常用的組合是perf top或者pidstat配合/proc/pid/status查看線程狀態(tài)。生產(chǎn)環(huán)境不一定有perf權(quán)限這時候strace -p pid可以看系統(tǒng)調(diào)用但注意strace在高頻進程上有嚴(yán)重性能開銷使用前要評估影響。排查CPU問題時的三個容易翻車的點第一別忽略內(nèi)核態(tài)sy過高。如果sy持續(xù)超過30%多半是有系統(tǒng)調(diào)用風(fēng)暴比如頻繁的網(wǎng)絡(luò)收發(fā)、鎖競爭、或硬件中斷處理過多。用top按CPU排序時如果排前面的都是ksoftirqd或kworker這類內(nèi)核線程就得檢查是不是網(wǎng)卡軟中斷在某個CPU上集中觸發(fā)。查看/proc/interrupts能確認(rèn)中斷分布是否均勻必要時調(diào)整網(wǎng)卡隊列的RPSReceive Packet Steering設(shè)置。第二當(dāng)心上下文切換過高。vmstat的cs列持續(xù)幾十萬說明系統(tǒng)在瘋狂切換進程/線程CPU資源大量消耗在“換人”而不是“干活”上。常見誘因是線程池開得過大、鎖競爭嚴(yán)重或者定時器頻繁觸發(fā)。我處理過一個案例應(yīng)用線程池配置了200個線程但活躍線程只有幾個大量線程在鎖上等待上下文切換高得嚇人把CPU全部浪費完了。把線程池調(diào)小之后性能反而上去了。第三CPU綁核相關(guān)的隱蔽問題。多核環(huán)境下如果進程頻繁在不同CPU核之間遷移緩存命中率下降也會造成CPU使用率偏高。NUMA架構(gòu)下跨節(jié)點訪問內(nèi)存更是性能殺手。排查看/proc/pid/numa_maps能發(fā)現(xiàn)內(nèi)存是否跨節(jié)點分布必要時調(diào)整進程的NUMA策略。3. 內(nèi)存與SwapOOM不是終點只是起點3.1 內(nèi)存問題的排查順序內(nèi)存排查我先看三條命令的輸出free -h vmstat 1 5 dmesg -T | tail -50free -h看總量、已用、可用和Swap使用情況。有個細節(jié)必須說清楚Linux的free輸出里available才是真正可分配給新進程的內(nèi)存量而不是free列。因為buff/cache在內(nèi)存壓力下能回收所以一臺內(nèi)存用了90%的機器如果available還有30%系統(tǒng)并不會觸發(fā)OOM。vmstat重點看siswap in和soswap out。如果這兩個值持續(xù)不為0說明物理內(nèi)存已經(jīng)不夠用系統(tǒng)在靠Swap硬撐。注從磁盤換進換出內(nèi)存頁的性能損耗極大比直接物理內(nèi)存訪問慢好幾個數(shù)量級。我見過一臺數(shù)據(jù)庫服務(wù)器Swap使用了8GB查詢延遲翻了幾十倍就是這個原因。dmesg一定要看因為OOM Killer殺進程時會在內(nèi)核日志里留下完整記錄包括誰觸發(fā)了OOM、當(dāng)時內(nèi)存最緊張的進程是誰、回收了多少內(nèi)存。日志里通常還有這樣一行Out of memory: Killed process 12345 (java) total-vm:...。這是定位“誰殺了我的進程”的最直接證據(jù)。3.2 OOM的深層原因很多人以為OOM就是“內(nèi)存不夠了”其實背后還有幾種情況。一是內(nèi)存碎片化。物理內(nèi)存總量還有不少但連續(xù)的“大塊”內(nèi)存滿足不了應(yīng)用的需求而Linux默認(rèn)啟用的是虛存管理可能無法有效處理大塊連續(xù)分配。密集的內(nèi)核對于這類請求會失敗、觸發(fā)OOM。這種情況跟應(yīng)用申請大塊內(nèi)存比如JVM堆、搜索引擎倒排索引加載有關(guān)系。/proc/buddyinfo能看到內(nèi)存碎片狀況如果高階塊全為0基本可以判斷是碎片問題。二是內(nèi)存泄漏。應(yīng)用長時間運行內(nèi)存只漲不降最終觸發(fā)OOM。排內(nèi)存泄漏我通常用ps aux --sort-rss看RSS排序鎖定增長異常的那個進程然后配合監(jiān)控確認(rèn)它的內(nèi)存趨勢。我實習(xí)帶過一個案例一個后端服務(wù)每處理一次請求就多占用幾MB內(nèi)存跑三天就OOM最后定位是代碼里某個緩存在無限增長沒有清理。這種問題排查的難度不在定位而在于需要長時間觀察所以建議監(jiān)控告警里一定要有進程內(nèi)存的趨勢曲線。三是Cgroup限制。容器環(huán)境里最常見宿主機還有大把內(nèi)存但容器內(nèi)的Cgroup內(nèi)存限制到了一樣觸發(fā)OOM。排查時不要只看宿主機free要檢查容器的Cgroup使用量cat /sys/fs/cgroup/memory/memory.usage_in_bytes cat /sys/fs/cgroup/memory/memory.limit_in_bytes3.3 Swap的正確配置姿勢關(guān)于Swap不同的場景有不同的處理方式。數(shù)據(jù)庫這類延遲敏感型的服務(wù)我通常建議降低swappiness——這個內(nèi)核參數(shù)控制內(nèi)核傾向于換出內(nèi)存頁的程度取值范圍0~100默認(rèn)通常是60。數(shù)字越大內(nèi)核越積極使用Swap。降低到10甚至個別場景直接關(guān)掉Swap能讓數(shù)據(jù)庫盡量留在物理內(nèi)存里。但對于一些批處理型任務(wù)或者內(nèi)存峰值明顯的應(yīng)用留部分Swap做兜底其實是保護機制防止運營高峰期直接OOM。這就需要在監(jiān)控上看到 Swap 使用明顯上升時就要發(fā)出預(yù)警因為通常應(yīng)用程序會因內(nèi)存壓力劇烈波動而性能急劇下降。在修改swappiness參數(shù)時用sysctl vm.swappiness10可以臨時生效要持久化需要寫到/etc/sysctl.conf里。修改之前先看當(dāng)前值改完之后用sysctl -p重載。有一點要記牢這個參數(shù)只影響內(nèi)核換出的“積極性”不會適配應(yīng)用都禁用Swap。在計劃禁用時你得保證應(yīng)用內(nèi)存峰值確確實實低于物理內(nèi)存容量否則就是在賭運氣。4. 磁盤與文件系統(tǒng)空間滿只是最淺的一層4.1 兩個容易搞混的“滿”磁盤滿分兩種容量滿和inode滿。前者好理解后者是很多新手沒概念的東西。inode可以理解為文件系統(tǒng)的“戶口本”每個文件都要占一條記錄。如果小文件特別多可能容量還有剩但inode已經(jīng)用完表現(xiàn)為“No space left on device”。排查命令分別用df -h和df -i。如果df -h顯示還有幾十GB但寫入文件報錯磁盤滿第一反應(yīng)就該查df -i。我在一個日志采集服務(wù)器上遇到過這個問題每天產(chǎn)生上千萬個小日志文件日志輪轉(zhuǎn)配置沒做好一個月之后inode耗盡。當(dāng)時df -h才用了60%但整個分區(qū)再也寫不進任何數(shù)據(jù)。處理inode耗盡的思路找到哪個目錄文件數(shù)量最多通常用for d in /var/log /tmp /home /data; do echo $d; find $d -xdev -type f | wc -l; done先定位再清理。事后一定要把日志輪轉(zhuǎn)logrotate策略修正甚至把應(yīng)用改為按時間分批存儲大文件減少小文件數(shù)量。這里多說一句很多 NoSQL 存儲和消息隊列產(chǎn)生的“小文件堆積”問題根子都出在業(yè)務(wù)設(shè)計時沒考慮文件數(shù)量而不只是運維配置的鍋。4.2 找出誰在偷偷占空間du -sh /*從根往下逐層定位是排查“容量滿”的最高效方式。小技巧定位到具體目錄后用du -sh /目錄/* | sort -hr | head -20列出最大的一批文件。注意du在大目錄上會很慢特別是包含大量小文件的情況優(yōu)先用--max-depth1限制層級??赡苡信笥延龅竭^這種情況du -sh /加總算出來的總量遠小于df -h顯示的已用空間。這不是統(tǒng)計誤差最常見的原因是“文件被刪除但進程還持有句柄”。進程打開了一個文件rm刪除了它但從內(nèi)核的角度這個文件仍然存在直到持有它的進程把句柄關(guān)閉才會真正釋放磁盤塊。這就是為什么df顯示空間滿但du找不到大文件。排查命令lsof L1它會列出所有“被刪除但仍被進程打開”的文件包括大小??吹浇Y(jié)果后找到占空間最大的那個評估它屬于哪個進程。如果進程沒法重啟可以嘗試用/proc/pid/fd/下的軟鏈接配合truncate -s 0清空文件內(nèi)容這招在遇到磁盤阻塞的情況下特別管用——不是真正截斷底層已刪除文件的內(nèi)容而是讓磁盤塊能被系統(tǒng)回收。磁盤空間滿還有一個容易被忽視的點root用戶的保留空間。Ext4文件系統(tǒng)默認(rèn)給root預(yù)留5%的空間這是為了避免普通用戶把磁盤寫滿后系統(tǒng)無法正常運作。對于大容量分區(qū)5%可能浪費幾十GB對于家目錄這類分區(qū)可以調(diào)小但對根分區(qū)我建議保留。調(diào)預(yù)留比例用tune2fs -m 2 /dev/mapper/xx-root修改前先用dumpe2fs查看當(dāng)前保留塊設(shè)置。4.3 I/O瓶頸用iostat和iotop精準(zhǔn)定位當(dāng)vmstat的wa值高時I/O層面要立刻轉(zhuǎn)場排查。第一步iostat -x 1 5看%util、await、svctm這幾個參數(shù)。很多人有個誤解認(rèn)為%util達到100%就是磁盤“滿了”其實%util表示設(shè)備忙但不代表無法服務(wù)更多請求。如果%util只有30%但await已經(jīng)很高可能是有請求在隊列里排隊或者底層設(shè)備比如磁盤陣列控制器出現(xiàn)了性能瓶頸又或者請求大小和模式不合理導(dǎo)致單次I/O延遲高。定位到具體是哪些進程在刷盤用iotop或pidstat -d 1。這類工具需要權(quán)限如果沒有可以先把block_dump監(jiān)測器打開或者用bcc工具庫里的biosnoop追蹤I/O事件。生產(chǎn)環(huán)境里我定位過幾次I/O相關(guān)的場景數(shù)據(jù)庫頻繁小寫刷新每次事務(wù)都要刷日志文件典型的同步寫模式在機械盤上延遲很大。優(yōu)化方向是緩存/批次寫入、獨立日志盤、或換SSD。日志收集工具并發(fā)讀大量文件緩存基本無法命中隨機讀I/O壓力巨大。某應(yīng)用 fork 了大量子進程后同時啟動每個子進程都要讀取共用的配置文件瞬間讀放大把I/O打滿。解決方案是把共享配置做成動態(tài)加載避免啟動時全量讀取。5. 網(wǎng)絡(luò)層故障連接問題的背后5.1 先分清是“不通”還是“拒絕”用戶說“連不上”背后可能是完全不同的故障。我要求團隊先跑三條命令ping 目標(biāo)IP ss -lntp | grep 端口 telnet 目標(biāo)IP 端口 或 nc -vz -w 3 目標(biāo)IP 端口ping不通說明網(wǎng)絡(luò)鏈路或?qū)Χ酥鳈C有問題也可能是防火墻攔截ICMP。但注意ping通不代表端口可用ping不通也不代表端口不可用——有些服務(wù)器出于安全考慮禁ICMP但業(yè)務(wù)端口正常。所以連通性測試只是第一步端口測試才是關(guān)鍵。telnet/nc連不上時要區(qū)分兩種情況連接超時timeout和拒絕連接refused。timeout通常意味著中間鏈路不通或者對端防火墻把包丟了用的是DROP策略refused說明包已經(jīng)送到對端但對端沒有進程監(jiān)聽該端口或者本機防火墻用的是REJECT策略。一個常見場景服務(wù)剛啟動還沒完全監(jiān)聽端口或者進程已經(jīng)掛掉但健康檢查還在探測這時候?qū)Χ藭豏ST表現(xiàn)就是refused。5.2 細看監(jiān)聽與連接狀態(tài)ss是現(xiàn)在的主流工具我之前的老同事還在用netstat但生產(chǎn)上ss信息更全、速度更快。看監(jiān)聽和連接狀態(tài)ss -lntp ss -s ss -ant | awk {print $1} | sort | uniq -css -s做總覽——當(dāng)前建了哪些連接、在等待的、在排隊的一目了然。重點看兩個異常狀態(tài)SYN-SENT大量堆積說明本機發(fā)出去的連接請求沒得到應(yīng)答多半是對端或中間網(wǎng)絡(luò)出問題TIME-WAIT堆積是正?,F(xiàn)象但如果量大到讓端口耗盡就需要調(diào)整內(nèi)核參數(shù)。針對高并發(fā)的短連接應(yīng)用場景比如網(wǎng)關(guān)TIME-WAIT過多是個經(jīng)典問題內(nèi)核參數(shù)調(diào)整要小心權(quán)衡net.ipv4.tcp_tw_reuse搭配tcp_timestamps可以在出站連接上復(fù)用TIME-WAIT連接但亂改可能引入連接復(fù)用的異常風(fēng)險。如果ss -lntp顯示監(jiān)聽隊列出現(xiàn)溢出Recv-Q堆積這是半連接隊列或全連接隊列滿的表現(xiàn)。全連接隊列溢出可以通過ss -lnt看到 Recv-Q 超過Send-Q來判斷原因通常是應(yīng)用處理連接速度跟不上新連接到達速度。排查時先看這幾點應(yīng)用線程數(shù)是否足夠、listener backlog設(shè)置是否偏小很多部署默認(rèn)值往往是128對于高并發(fā)場景明顯不夠調(diào)整為2048或以后、系統(tǒng)net.core.somaxconn是否同步調(diào)大。5.3 抓包定位問題鏈路網(wǎng)絡(luò)排查里最有力的終極大招就是抓包。tcpdump是必會工具簡單場景看三次握手階段是否有遺漏比如SYN發(fā)出去了對方不回SYN-ACK問題多半在網(wǎng)絡(luò)路徑或?qū)Χ朔阑饓θ绻荢YN-ACK回過來了但ACK不回問題可能出在本機的協(xié)議?;騭ocket隊列。tcpdump -i eth0 host 目標(biāo)IP and port 8080 -w /tmp/capture.pcap抓包文件用wireshark分析或者直接tcpdump -r看。抓包一般建議在問題的兩端分別抓對照時間戳。舉個例子一次偶發(fā)訪問變慢單機抓包看到TCP重傳頻繁換網(wǎng)絡(luò)設(shè)備側(cè)一起抓結(jié)果發(fā)現(xiàn)是中間交換機的鏈路聚合hash策略不均衡導(dǎo)致的單鏈路擁塞。這個案例說明網(wǎng)絡(luò)層問題不一定能通過看本機指標(biāo)定位出來跨節(jié)點抓包對照才是正解。DNS問題也是網(wǎng)絡(luò)排查中極高頻的痛點。表現(xiàn)為“某些域名時通時不通”、“首次訪問特別慢”。用dig trace可以看到解析鏈路的耗時在哪個環(huán)節(jié)/etc/resolv.conf檢查配置的DNS服務(wù)器是否合理。我排過的一個案例應(yīng)用配置的DNS服務(wù)器指向一個早已下線的內(nèi)網(wǎng)DNS解析超時后才走備用每次請求白白消耗5秒。把DNS配置改對后延遲驟降。6. 常用排查工具組合與監(jiān)控基線6.1 建立一套工具組合和排查字段用哪個工具不關(guān)鍵關(guān)鍵是你對輸出字段的含義是否了然于心。我給自己定了一套排查順序也推薦給團隊第一梯隊發(fā)現(xiàn)異常uptime、top、free、df、ss、dmesg第二梯隊關(guān)聯(lián)分析vmstat、iostat、sar、pidstat第三梯隊深挖定位strace、perf、tcpdump、lsof、gdbsar在我心里的地位比較特殊。新接手一臺機器我會先看它的歷史數(shù)據(jù)來確定“正常態(tài)”長什么樣。它能返回歷史某段時間的CPU、內(nèi)存、磁盤、網(wǎng)絡(luò)數(shù)據(jù)這是其他工具替代不了的——你沒有歷史數(shù)據(jù)怎么判斷現(xiàn)在的“異?!笔钦娴漠惓D赜行┠觐^久遠的監(jiān)控工具已經(jīng)部署好了但還是建議把sysstat裝好定時采樣默認(rèn)配置覆蓋范圍很廣別隨意關(guān)閉。排查時我習(xí)慣把“時間線”拉出來把系統(tǒng)報障時間、監(jiān)控告警時間、應(yīng)用日志報錯時間、內(nèi)核日志異常時間對齊。故障排查和刑偵差不多時間線對不上很大概率走彎路。舉例監(jiān)控顯示磁盤I/O 3點開始飆高但應(yīng)用發(fā)版是3點半業(yè)務(wù)量也是3點半才開始漲的說明I/O問題是先發(fā)生的業(yè)務(wù)變慢可能是I/O導(dǎo)致的結(jié)果而不是原因。這么一捋排查方向馬上糾正過來。6.2 監(jiān)控基線與告警閾值的設(shè)計思路運維工作一半在故障發(fā)生后的排查另外一半在故障發(fā)生之前的預(yù)警。我給客戶做方案時經(jīng)常強調(diào)“監(jiān)控基線”的概念。每臺服務(wù)器都有自己的“性格”有的業(yè)務(wù)本身就在夜間跑批CPU占滿很正常有的服務(wù)內(nèi)存就是會緩慢增長兩三個月重啟一次屬于正常節(jié)奏。盲目套用通用告警閾值只會讓告警失去可信度久而久之成了狼來了。建立基線的做法至少收集各個核心指標(biāo)的最近30天數(shù)據(jù)用百分比線進行建模。例如CPU使用率的P95第95百分位是60%那告警閾值設(shè)在80%比較合理——既不會頻繁誤報又能在真實異常出現(xiàn)時及時提醒。內(nèi)存監(jiān)控要重點關(guān)注available而非used磁盤監(jiān)控要同時看容量和inode網(wǎng)絡(luò)監(jiān)控除了流量還要看重傳率、丟包率。這些從故障處理中學(xué)到的經(jīng)驗應(yīng)該沉淀成監(jiān)控配置的標(biāo)準(zhǔn)。注意監(jiān)控不是越多越好過多的曲線只是在告警時增加噪音。先覆蓋能反映問題的關(guān)鍵指標(biāo)逐步迭代補齊。7. 典型故障復(fù)盤與避坑經(jīng)驗7.1 一個“空轉(zhuǎn)”CPU問題的完整復(fù)盤有一次同事反饋一臺應(yīng)用服務(wù)器響應(yīng)變慢我按順序排查top看到us30%sy40%負載卻不低。當(dāng)時第一反應(yīng)是系統(tǒng)調(diào)用異常。用pidstat找出占用高的進程再strace -c -p pid統(tǒng)計系統(tǒng)調(diào)用分布發(fā)現(xiàn)futex用戶態(tài)鎖調(diào)用次數(shù)高得離譜。繼續(xù)看線程棧發(fā)現(xiàn)大量線程堵在pthread_cond_wait同時業(yè)務(wù)線程和回收線程在共享資源上有極高的鎖競爭。確認(rèn)根因后修復(fù)方案是把原來的單鎖拆分成分段鎖同時調(diào)整了線程池大小。這個案例的關(guān)鍵點是如果只停在“CPU 使用率高”這個層面就盲目重啟下次故障很快又會出現(xiàn)。鎖競爭問題靠重啟是掩蓋不掉的。這個案例也說明有時候CPU的sy高并不只與內(nèi)核代碼路徑有關(guān)應(yīng)用層不合理的鎖使用同樣會引發(fā)內(nèi)核態(tài)的高開銷因為futex的實現(xiàn)正是大量動用內(nèi)核的系統(tǒng)調(diào)用。7.2 一次磁盤“離奇”占滿的排查記錄一個分區(qū)df顯示用量100%du -sh卻只統(tǒng)計出幾GB這一看就猜到有文件被刪了但進程沒釋放。執(zhí)行l(wèi)sof L1后看到一堆被日志進程打開、但文件名已經(jīng)帶(deleted)標(biāo)記的大文件總大小幾十GB。這些句柄屬于一個常駐進程理論上重啟進程能解決但生產(chǎn)環(huán)境不允許隨意重啟。當(dāng)時我用了一種更輕量的方式找到lsof顯示對應(yīng)進程的/proc/pid/fd/數(shù)字軟鏈接對其中一個 fd 執(zhí)行: /proc/pid/fd/數(shù)字或truncate -s 0把它的文件內(nèi)容清零讓磁盤塊被回收。這個辦法可以應(yīng)急但要注意直接對服務(wù)進行清空文件內(nèi)容操作雖然能快速釋放磁盤但后續(xù)日志寫入可能因為文件偏移量異常而出問題穩(wěn)妥方案還是盡快通知應(yīng)用方重啟、恢復(fù)日志輪轉(zhuǎn)配置。這個坑告訴我的經(jīng)驗是日志文件被刪除的現(xiàn)象遠比想象中頻繁add 一條帶大小排序的lsof L1巡檢腳本到運維工具箱里能節(jié)省很多救火時間。7.3 網(wǎng)絡(luò)“間歇性”超時的迷惑行為一個內(nèi)部服務(wù)偶發(fā)超時一個月被投訴兩次每次都是規(guī)律性地在業(yè)務(wù)高峰期出現(xiàn)。單查服務(wù)端負載不高網(wǎng)絡(luò)流量也不大往返延遲看起來正常。加了抓包后看到規(guī)律抓包客戶端在特定時間點出現(xiàn)多個TCP Dup ACK和重傳包。因為訪問鏈路上有一跳負載均衡設(shè)備它的連接跟蹤表老化機制在高連接數(shù)下會誤殺部分存活連接導(dǎo)致對端不斷重傳。繞過或調(diào)整硬件的會話保持參數(shù)后問題消失。這個案例值得記住的是網(wǎng)絡(luò)問題有鏈路設(shè)備和主機兩層很多偶發(fā)問題只在本機排查永遠找不到根本原因。要勇于跳出單機的視角沿著數(shù)據(jù)路徑從應(yīng)用端到服務(wù)端一步步驗證包括中間的所有設(shè)備。7.4 幾個可以直接“抄作業(yè)”的排查口訣帶新人時我常給幾句口訣也寫在這里供參考負載高先分三類計算型看usI/O型看wa鎖型看cs別繞彎。內(nèi)存不足看available別糾結(jié)free太小。磁盤報滿查兩處空間df -hinode 用df -i都滿了才叫滿。連接異常先分四類超時、拒絕、重置、卡住——對應(yīng)不同的排查方向。事前不理解事后不看記錄排查一萬次也就停留在表面。把每次故障的時間線、根因和修復(fù)方案寫進文檔才是成長最快的方式。7.5 關(guān)于工具權(quán)限與安全操作的提醒最后提一點安全事項。生產(chǎn)環(huán)境使用系統(tǒng)排查工具必須嚴(yán)格遵守“只讀優(yōu)先”的原則。像top、vmstat、iostat、ss、dmesg這些只讀命令可以放心使用但strace會停住目標(biāo)進程尤其高頻場景gdb介入更是停進程級操作使用前必須經(jīng)過審批并在低峰期執(zhí)行。另外涉及修改內(nèi)核參數(shù)的命令每次盡量只改一個參數(shù)并用sysctl -a驗證避免批量改動后無法確定問題來源。我自己有過一次教訓(xùn)為了一次性解決某個網(wǎng)絡(luò)問題我同時改了五六個TCP相關(guān)參數(shù)結(jié)果問題沒解決反而引入了新問題——最后花了一下午逐項調(diào)回去才恢復(fù)。從那以后我給自己立了一條規(guī)矩生產(chǎn)環(huán)境的任何調(diào)整都要“小步快走、可回退、留記錄”。寫在這個內(nèi)容之后做運維這些年我最大的體會是故障排查能力不是靠背命令練出來的而是靠一次次故障后的復(fù)盤積累出來的。工具是固定的系統(tǒng)的機制是清晰的難的是如何在緊急情況下冷靜地按著鏈路走不被表象帶偏。如果你剛?cè)胄薪ㄗh從今天開始做一個記錄每次遇到故障把時間線、現(xiàn)象、排查動作、根因、修復(fù)方案寫清楚。堅持半年你再看故障視角會完全不同。還有一點多讀內(nèi)核文檔和系統(tǒng)源碼中對調(diào)度、內(nèi)存、網(wǎng)絡(luò)機制的解釋本質(zhì)上排查功夫的深淺其實就看你對系統(tǒng)機制理解的深淺。