錯(cuò)排查實(shí)戰(zhàn):從告警到根因定位)
1. 從一次凌晨告警說(shuō)起WRITE_BLOCK 報(bào)錯(cuò)到底在說(shuō)什么凌晨?jī)牲c(diǎn)多集群監(jiān)控突然推來(lái)一批告警核心鏈路的寫入任務(wù)大面積超時(shí)。登錄到出問(wèn)題的 DataNode 節(jié)點(diǎn)上翻日志滿屏都是同一句話DataXceiver error processing WRITE_BLOCK operation。這個(gè)報(bào)錯(cuò)在分布式存儲(chǔ)運(yùn)維里算是老熟人了但每次出現(xiàn)的原因都不太一樣處理起來(lái)不能一概而論。先把這句話拆開(kāi)看。DataXceiver是 DataNode 內(nèi)部負(fù)責(zé)處理數(shù)據(jù)讀寫請(qǐng)求的工作線程每一個(gè)來(lái)自客戶端或者其他 DataNode 的數(shù)據(jù)傳輸請(qǐng)求都會(huì)交給一個(gè) DataXceiver 線程去處理。WRITE_BLOCK operation指的是寫數(shù)據(jù)塊這個(gè)具體操作。所以整句話的字面意思是DataNode 在處理寫數(shù)據(jù)塊請(qǐng)求時(shí)拋出了異常。它本身是一個(gè)外層包裝異常真正的原因往往藏在后面的堆?;蛘逤aused by里。很多人第一次遇到這個(gè)報(bào)錯(cuò)會(huì)慌因?yàn)樗雌饋?lái)像是數(shù)據(jù)丟了或者磁盤壞了。實(shí)際上絕大多數(shù)情況下它只是某一次寫塊請(qǐng)求失敗了HDFS 本身有副本機(jī)制和管線恢復(fù)機(jī)制單次失敗通常不會(huì)導(dǎo)致數(shù)據(jù)丟失。真正需要關(guān)注的是為什么失敗、失敗頻率有多高、是否影響到了上層任務(wù)的可用性。這篇內(nèi)容適合誰(shuí)看如果你正在維護(hù)一套 HDFS 集群或者負(fù)責(zé)基于 HDFS 的數(shù)據(jù)平臺(tái)被這個(gè)報(bào)錯(cuò)反復(fù)騷擾過(guò)那這篇就是寫給你的。我會(huì)從報(bào)錯(cuò)的觸發(fā)鏈路講起把常見(jiàn)的幾類根因拆開(kāi)給出可復(fù)現(xiàn)的排查步驟最后分享幾個(gè)我在實(shí)際處理中踩過(guò)的坑和總結(jié)出來(lái)的經(jīng)驗(yàn)。全文基于常見(jiàn)的生產(chǎn)實(shí)踐整理具體參數(shù)請(qǐng)以你自己集群的實(shí)際情況為準(zhǔn)。需要先明確一個(gè)認(rèn)知WRITE_BLOCK失敗從來(lái)不是孤立事件它背后一定對(duì)應(yīng)著某個(gè)資源維度出了問(wèn)題——磁盤、網(wǎng)絡(luò)、內(nèi)存、線程、配置或者上游客戶端的異常行為。排查的核心思路就是順著寫管線把每一段都驗(yàn)證一遍而不是盯著這一行日志反復(fù)看。2. 寫塊請(qǐng)求的完整鏈路先搞清楚失敗發(fā)生在哪一段要排查這個(gè)報(bào)錯(cuò)得先知道一次WRITE_BLOCK請(qǐng)求從發(fā)起到完成中間經(jīng)過(guò)了哪些環(huán)節(jié)。只有把鏈路畫清楚才能定位到具體是哪一段斷了。2.1 客戶端發(fā)起寫請(qǐng)求到 DataNode 接收的流程當(dāng)客戶端要寫一個(gè)文件時(shí)它先向 NameNode 申請(qǐng)創(chuàng)建文件NameNode 返回一組 DataNode 列表默認(rèn) 3 副本構(gòu)成一條寫管線pipeline??蛻舳税褦?shù)據(jù)切成 packet發(fā)給管線上的第一個(gè) DataNode。第一個(gè) DataNode 收到后一邊往本地磁盤寫一邊把 packet 轉(zhuǎn)發(fā)給第二個(gè) DataNode第二個(gè)再轉(zhuǎn)發(fā)給第三個(gè)。這個(gè)轉(zhuǎn)發(fā)過(guò)程用的就是DataXceiver線程。每個(gè) DataNode 上會(huì)有一個(gè)DataXceiverServer在監(jiān)聽(tīng)數(shù)據(jù)傳輸端口默認(rèn) 50010 或新版本的 9866每來(lái)一個(gè)連接就 fork 一個(gè)DataXceiver線程去處理。所以DataXceiver error processing WRITE_BLOCK operation這個(gè)報(bào)錯(cuò)可能出現(xiàn)在管線上的任意一個(gè)節(jié)點(diǎn)不一定是你最初懷疑的那個(gè)。關(guān)鍵點(diǎn)在于報(bào)錯(cuò)日志里通常會(huì)帶上block的標(biāo)識(shí)和datanode的信息還會(huì)有一個(gè)Caused by。如果你只看到外層這一句說(shuō)明日志被截?cái)嗔诵枰シ暾亩褩!_@一點(diǎn)后面會(huì)專門講。2.2 管線上的三個(gè)角色與各自的失敗表現(xiàn)寫管線上有三種角色它們的失敗表現(xiàn)和排查重點(diǎn)完全不同角色職責(zé)典型失敗表現(xiàn)排查重點(diǎn)管線首節(jié)點(diǎn)接收客戶端數(shù)據(jù)并轉(zhuǎn)發(fā)報(bào)錯(cuò)常伴隨客戶端連接超時(shí)網(wǎng)絡(luò)、線程數(shù)、接收緩沖區(qū)管線中間節(jié)點(diǎn)接收上游并轉(zhuǎn)發(fā)下游報(bào)錯(cuò)常伴隨上游節(jié)點(diǎn)重試磁盤 IO、下游連通性管線末節(jié)點(diǎn)只接收不轉(zhuǎn)發(fā)報(bào)錯(cuò)多為本地磁盤寫入失敗磁盤空間、磁盤健康、權(quán)限理解這個(gè)表格很重要。比如你發(fā)現(xiàn)報(bào)錯(cuò)總是集中在某幾個(gè)節(jié)點(diǎn)而且這些節(jié)點(diǎn)都是管線末節(jié)點(diǎn)那大概率是磁盤問(wèn)題如果報(bào)錯(cuò)隨機(jī)分布且伴隨大量連接超時(shí)那更可能是網(wǎng)絡(luò)或者線程資源問(wèn)題。2.3 為什么這個(gè)報(bào)錯(cuò)容易被誤判我見(jiàn)過(guò)不少團(tuán)隊(duì)一看到WRITE_BLOCK失敗第一反應(yīng)就是磁盤壞了然后急急忙忙去換盤。結(jié)果換完盤發(fā)現(xiàn)報(bào)錯(cuò)還在白白折騰一場(chǎng)。原因就在于這個(gè)報(bào)錯(cuò)是外層包裝它把底層各種異常都統(tǒng)一成了這一句話。常見(jiàn)的Caused by包括java.io.IOException: Too many open files、java.net.SocketTimeoutException、java.nio.channels.ClosedChannelException、DiskOutOfSpaceException、java.io.EOFException等等。每一種對(duì)應(yīng)的根因和處理方式都不一樣。所以排查的第一步永遠(yuǎn)是拿到完整的異常堆??辞宄?Caused by 是什么。提示如果日志里只有外層這一句先檢查日志配置是否把堆棧截?cái)嗔嘶蛘呷?DataNode 的hadoop-hdfs-datanode-*.log里搜索同一個(gè) block id通常能找到更完整的上下文。3. 按 Caused by 分類五類高頻根因的定位方法拿到完整堆棧之后就可以按 Caused by 來(lái)分類處理了。下面這五類是我在實(shí)際運(yùn)維中遇到頻率最高的基本覆蓋了八成以上的場(chǎng)景。3.1 磁盤類空間不足、壞盤與 IO 瓶頸磁盤問(wèn)題是最直觀的一類。DiskOutOfSpaceException說(shuō)明 DataNode 的數(shù)據(jù)目錄寫滿了。HDFS 有預(yù)留空間機(jī)制當(dāng)某個(gè)數(shù)據(jù)目錄的可用空間低于閾值由dfs.datanode.du.reserved控制默認(rèn) 0但很多生產(chǎn)環(huán)境會(huì)設(shè)置成幾十 GBDataNode 就會(huì)拒絕往這個(gè)目錄寫。排查方法很直接# 查看各數(shù)據(jù)目錄的使用率 df -h | grep -E data|hdfs # 查看 DataNode 數(shù)據(jù)目錄配置 grep -A5 dfs.datanode.data.dir /path/to/hdfs-site.xml如果確認(rèn)是空間問(wèn)題處理方式有兩種一是清理過(guò)期數(shù)據(jù)或者調(diào)整副本策略釋放空間二是臨時(shí)調(diào)低dfs.datanode.du.reserved不推薦長(zhǎng)期這么做。更根本的做法是擴(kuò)容或者做數(shù)據(jù)均衡。壞盤的表現(xiàn)則更隱蔽。磁盤可能還有空間但讀寫出現(xiàn)大量錯(cuò)誤日志里會(huì)出現(xiàn)Input/output error或者DiskChecker相關(guān)的報(bào)錯(cuò)。這時(shí)候要用smartctl之類的工具檢查磁盤健康狀態(tài)確認(rèn)是物理壞道還是文件系統(tǒng)損壞。IO 瓶頸是另一回事。磁盤沒(méi)壞、空間也夠但 IO 被打滿了導(dǎo)致寫塊超時(shí)。這種情況通常伴隨SocketTimeoutException因?yàn)?DataNode 在規(guī)定時(shí)間內(nèi)沒(méi)寫完上游等不及就斷了。排查時(shí)看iostat -x 1的%util和await指標(biāo)如果%util長(zhǎng)期接近 100%說(shuō)明磁盤已經(jīng)是瓶頸了。3.2 網(wǎng)絡(luò)類連接超時(shí)、丟包與帶寬打滿網(wǎng)絡(luò)問(wèn)題在跨機(jī)架、跨機(jī)房部署的集群里特別常見(jiàn)。SocketTimeoutException和ClosedChannelException是典型表現(xiàn)。寫管線是串行的任何一個(gè)節(jié)點(diǎn)之間的網(wǎng)絡(luò)抖動(dòng)都會(huì)導(dǎo)致整條管線失敗。排查網(wǎng)絡(luò)問(wèn)題我一般按這個(gè)順序來(lái)先用ping和traceroute確認(rèn)基礎(chǔ)連通性和路由是否正常。用netstat -s看有沒(méi)有大量的重傳retransmit和丟包統(tǒng)計(jì)。用iftop或者sar -n DEV 1看網(wǎng)卡帶寬是否被打滿。檢查交換機(jī)端口是否有 CRC 錯(cuò)誤或者丟包計(jì)數(shù)。帶寬打滿是個(gè)容易被忽略的點(diǎn)。HDFS 寫數(shù)據(jù)本身就很吃帶寬如果同一臺(tái)機(jī)器上還跑了其他吃帶寬的服務(wù)比如另一個(gè)大數(shù)據(jù)組件就容易互相擠占。我遇到過(guò)一臺(tái) DataNode 上同時(shí)跑了數(shù)據(jù)同步任務(wù)把網(wǎng)卡跑滿導(dǎo)致 HDFS 寫塊頻繁超時(shí)。后來(lái)把任務(wù)錯(cuò)峰調(diào)度就解決了。3.3 資源類文件句柄、線程數(shù)與內(nèi)存Too many open files是資源類問(wèn)題里最經(jīng)典的。DataNode 每個(gè)連接、每個(gè)塊文件都要占用文件句柄如果ulimit -n設(shè)置得太小或者句柄泄漏就會(huì)在寫塊時(shí)失敗。檢查方法# 查看 DataNode 進(jìn)程的句柄限制 cat /proc/$(pgrep -f DataNode)/limits | grep open files # 查看當(dāng)前打開(kāi)的句柄數(shù) ls /proc/$(pgrep -f DataNode)/fd | wc -l如果發(fā)現(xiàn)句柄數(shù)接近上限要么調(diào)大ulimit要么排查是否有句柄泄漏。句柄泄漏通常和某些異常路徑?jīng)]有正確關(guān)閉流有關(guān)需要結(jié)合代碼或者版本已知問(wèn)題來(lái)判斷。線程數(shù)問(wèn)題表現(xiàn)為DataXceiver線程創(chuàng)建失敗。DataNode 對(duì)并發(fā)傳輸線程數(shù)是有上限的dfs.datanode.max.transfer.threads默認(rèn) 4096。如果并發(fā)寫請(qǐng)求特別多線程池被打滿新的寫請(qǐng)求就會(huì)被拒絕。這種情況在高負(fù)載集群里會(huì)出現(xiàn)表現(xiàn)為報(bào)錯(cuò)集中在業(yè)務(wù)高峰期。內(nèi)存問(wèn)題相對(duì)少見(jiàn)但也不能忽視。DataNode 的堆內(nèi)存如果設(shè)置過(guò)小在大量并發(fā)寫的時(shí)候可能觸發(fā)頻繁 GC導(dǎo)致處理變慢甚至 OOM???GC 日志和jstat輸出能快速判斷。3.4 配置類超時(shí)參數(shù)與副本策略不匹配配置問(wèn)題往往是最冤的一類因?yàn)橛布途W(wǎng)絡(luò)都沒(méi)問(wèn)題就是參數(shù)沒(méi)調(diào)好。幾個(gè)關(guān)鍵參數(shù)值得關(guān)注參數(shù)默認(rèn)值作用調(diào)優(yōu)建議dfs.client.socket-timeout60s客戶端讀寫超時(shí)高延遲網(wǎng)絡(luò)可適當(dāng)調(diào)大dfs.datanode.socket.write.timeout480sDataNode 寫超時(shí)大塊寫入場(chǎng)景可調(diào)大dfs.datanode.max.transfer.threads4096最大傳輸線程數(shù)高并發(fā)集群需調(diào)大dfs.datanode.du.reserved0預(yù)留磁盤空間生產(chǎn)環(huán)境建議設(shè)置這些參數(shù)之間是有聯(lián)動(dòng)關(guān)系的。比如你把客戶端超時(shí)調(diào)得很短但網(wǎng)絡(luò)延遲本來(lái)就高那就會(huì)頻繁超時(shí)反過(guò)來(lái)超時(shí)調(diào)得太長(zhǎng)故障發(fā)現(xiàn)就會(huì)變慢。我的經(jīng)驗(yàn)是先測(cè)量實(shí)際的 P99 寫入延遲再據(jù)此設(shè)置超時(shí)留出 2 到 3 倍的余量。副本策略不匹配也會(huì)引發(fā)問(wèn)題。比如某些目錄設(shè)置了很高的副本數(shù)但集群節(jié)點(diǎn)數(shù)不夠?qū)е聦懝芫€無(wú)法湊齊足夠的節(jié)點(diǎn)寫塊自然就失敗了。3.5 客戶端類上游異常行為引發(fā)的連鎖反應(yīng)有時(shí)候問(wèn)題不在 DataNode而在客戶端。比如客戶端程序有 bug寫數(shù)據(jù)時(shí)頻繁創(chuàng)建和關(guān)閉連接導(dǎo)致 DataNode 端連接數(shù)暴漲或者客戶端寫入速度遠(yuǎn)超 DataNode 處理能力把管線壓垮。還有一種情況是客戶端所在機(jī)器資源不足比如客戶端自己的網(wǎng)絡(luò)或者磁盤有問(wèn)題導(dǎo)致它發(fā)給 DataNode 的數(shù)據(jù)本身就是殘缺的DataNode 校驗(yàn)失敗后報(bào)錯(cuò)。這類問(wèn)題的排查需要同時(shí)看客戶端日志和 DataNode 日志把兩邊的時(shí)間線對(duì)齊。我處理過(guò)一個(gè)案例某任務(wù)在特定時(shí)間段必然失敗查了半天 DataNode 沒(méi)問(wèn)題最后發(fā)現(xiàn)是客戶端所在機(jī)器在那個(gè)時(shí)間段有定時(shí)任務(wù)在跑搶占了資源。這種跨組件的關(guān)聯(lián)問(wèn)題單看 HDFS 日志是看不出來(lái)的。4. 一套可復(fù)現(xiàn)的排查流程從告警到定位根因前面講了分類這一節(jié)把排查流程串起來(lái)給一套可以直接照著做的步驟。這套流程我在多個(gè)集群上驗(yàn)證過(guò)基本能在半小時(shí)內(nèi)定位到大部分問(wèn)題。4.1 第一步確認(rèn)影響范圍與失敗頻率不要一上來(lái)就扎進(jìn)單條日志。先回答幾個(gè)問(wèn)題是單節(jié)點(diǎn)還是多節(jié)點(diǎn)是偶發(fā)還是持續(xù)影響的是所有寫入還是特定任務(wù)# 統(tǒng)計(jì)最近一小時(shí)內(nèi)報(bào)錯(cuò)涉及的節(jié)點(diǎn) grep DataXceiver error processing WRITE_BLOCK /var/log/hadoop-hdfs/*.log | \ awk -F[: ] {print $4} | sort | uniq -c | sort -rn # 統(tǒng)計(jì)報(bào)錯(cuò)頻率按分鐘 grep DataXceiver error processing WRITE_BLOCK /var/log/hadoop-hdfs/*.log | \ awk {print substr($2,1,5)} | uniq -c如果報(bào)錯(cuò)集中在單節(jié)點(diǎn)重點(diǎn)查那臺(tái)機(jī)器的磁盤和網(wǎng)絡(luò)如果分散在多節(jié)點(diǎn)重點(diǎn)查集群級(jí)別的資源或者客戶端行為如果只在特定時(shí)間段出現(xiàn)重點(diǎn)查那個(gè)時(shí)間段的負(fù)載情況。4.2 第二步抓取完整堆棧與關(guān)聯(lián)上下文拿到報(bào)錯(cuò)所在的日志文件后用 block id 把相關(guān)的日志都撈出來(lái)# 假設(shè) block id 是 BP-xxx-192.168.1.1-1234567890 grep BP-xxx-192.168.1.1-1234567890 /var/log/hadoop-hdfs/*.log重點(diǎn)看Caused by那一行以及報(bào)錯(cuò)前后幾秒內(nèi)同一節(jié)點(diǎn)上的其他日志。很多時(shí)候真正的根因日志就在報(bào)錯(cuò)的前幾行比如磁盤告警、GC 日志、連接拒絕等。4.3 第三步按維度逐項(xiàng)驗(yàn)證拿到 Caused by 之后按下面的清單逐項(xiàng)驗(yàn)證磁盤df -h看空間iostat -x 1看 IOsmartctl -a看健康。網(wǎng)絡(luò)ping、traceroute、netstat -s、sar -n DEV 1。資源ulimit、/proc/pid/fd、jstat -gc、top -H。配置核對(duì)hdfs-site.xml和core-site.xml里的關(guān)鍵參數(shù)??蛻舳丝纯蛻舳巳罩敬_認(rèn)寫入模式是否異常。這一步的關(guān)鍵是用數(shù)據(jù)說(shuō)話不要憑感覺(jué)。比如懷疑磁盤慢就拿出iostat的數(shù)據(jù)懷疑網(wǎng)絡(luò)丟包就拿出netstat -s的重傳計(jì)數(shù)。4.4 第四步驗(yàn)證修復(fù)效果定位到根因并處理后不能只看報(bào)錯(cuò)有沒(méi)有消失還要驗(yàn)證寫入性能是否恢復(fù)正常。我一般會(huì)跑一個(gè)小的寫入測(cè)試# 寫入一個(gè)測(cè)試文件觀察是否成功和耗時(shí) hdfs dfs -Ddfs.client.socket-timeout120000 -put /tmp/testfile /tmp/testfile_hdfs # 查看文件塊分布和副本狀態(tài) hdfs fsck /tmp/testfile_hdfs -files -blocks -locations如果測(cè)試通過(guò)且耗時(shí)正常再觀察一段時(shí)間線上任務(wù)的報(bào)錯(cuò)率。確認(rèn)穩(wěn)定后把這次的根因和處理過(guò)程記錄下來(lái)形成知識(shí)庫(kù)下次遇到類似問(wèn)題能快速響應(yīng)。5. 幾個(gè)真實(shí)踩坑案例教科書不會(huì)告訴你的細(xì)節(jié)理論講完了分享幾個(gè)我在實(shí)際處理中踩過(guò)的坑。這些細(xì)節(jié)在官方文檔里基本找不到但往往就是解決問(wèn)題的關(guān)鍵。5.1 案例一句柄數(shù)夠用但句柄泄漏了有一次集群報(bào)Too many open files我第一反應(yīng)是調(diào)大ulimit。調(diào)完之后確實(shí)好了幾天但很快又復(fù)現(xiàn)。后來(lái)用lsof分析發(fā)現(xiàn)DataNode 進(jìn)程的句柄數(shù)在緩慢增長(zhǎng)說(shuō)明有泄漏。進(jìn)一步排查發(fā)現(xiàn)是某個(gè)版本的已知問(wèn)題在特定異常路徑下塊文件的輸入流沒(méi)有正確關(guān)閉。升級(jí)到修復(fù)版本后問(wèn)題消失。這個(gè)案例的教訓(xùn)是句柄數(shù)不夠有兩種可能一種是限制太小一種是泄漏處理方式完全不同。前者調(diào)參數(shù)后者要升級(jí)或者打補(bǔ)丁。5.2 案例二磁盤沒(méi)滿但 inode 用完了df -h顯示磁盤還有 30% 空間但寫塊就是失敗。查了半天才發(fā)現(xiàn)是 inode 用完了。HDFS 會(huì)為每個(gè)塊創(chuàng)建多個(gè)文件數(shù)據(jù)文件、校驗(yàn)文件、元數(shù)據(jù)文件如果集群里小文件特別多inode 消耗會(huì)非??臁? 查看 inode 使用情況 df -i這個(gè)坑的隱蔽性在于df -h和df -i是兩個(gè)維度很多人只看前者。解決辦法是治理小文件或者調(diào)整 DataNode 的塊文件組織方式新版本有相關(guān)優(yōu)化。5.3 案例三網(wǎng)絡(luò)看起來(lái)正常但 MTU 不匹配跨機(jī)架通信時(shí)如果兩端 MTU 設(shè)置不一致大包會(huì)被分片或者丟棄表現(xiàn)為偶發(fā)的寫塊失敗。ping小包正常但ping -s 1472大包就丟。這種問(wèn)題在混合網(wǎng)絡(luò)環(huán)境里特別常見(jiàn)。排查方法# 測(cè)試大包連通性 ping -M do -s 1472 target_ip如果大包不通就要檢查兩端的 MTU 配置和交換機(jī)設(shè)置。這個(gè)坑我踩過(guò)一次查了整整一天最后發(fā)現(xiàn)是某臺(tái)新加入的機(jī)器 MTU 沒(méi)對(duì)齊。5.4 案例四GC 停頓導(dǎo)致的假性超時(shí)DataNode 堆內(nèi)存設(shè)置偏小在高峰期頻繁 Full GC每次停頓幾秒。寫塊請(qǐng)求在 GC 期間被掛起超過(guò)客戶端超時(shí)時(shí)間就報(bào)錯(cuò)了。表面看是網(wǎng)絡(luò)超時(shí)實(shí)際是 GC 問(wèn)題。判斷方法把 GC 日志和報(bào)錯(cuò)時(shí)間線對(duì)齊如果報(bào)錯(cuò)總是出現(xiàn)在 GC 停頓之后基本就能確認(rèn)。解決辦法是調(diào)大堆內(nèi)存或者優(yōu)化 GC 參數(shù)。6. 預(yù)防勝于救火把 WRITE_BLOCK 失敗擋在發(fā)生之前排查和修復(fù)是事后手段真正省心的做法是提前預(yù)防。這一節(jié)分享幾個(gè)我在日常運(yùn)維中堅(jiān)持做的動(dòng)作。6.1 監(jiān)控指標(biāo)要盯住這幾個(gè)與其等報(bào)錯(cuò)不如盯住幾個(gè)關(guān)鍵指標(biāo)在問(wèn)題惡化前就介入磁盤使用率和 inode 使用率設(shè)置閾值告警比如 80% 就提醒。磁盤 IO 的 await 和 %util長(zhǎng)期高位說(shuō)明磁盤是瓶頸。DataNode 的句柄數(shù)和線程數(shù)接近上限就要處理。GC 停頓時(shí)間單次超過(guò) 1 秒就要關(guān)注。網(wǎng)絡(luò)重傳率持續(xù)升高說(shuō)明網(wǎng)絡(luò)質(zhì)量在下降。這些指標(biāo)用常見(jiàn)的監(jiān)控系統(tǒng)都能采集到關(guān)鍵是要設(shè)置合理的閾值并且有人響應(yīng)。6.2 參數(shù)配置的幾條經(jīng)驗(yàn)參數(shù)沒(méi)有萬(wàn)能值但有幾條經(jīng)驗(yàn)可以借鑒dfs.datanode.du.reserved一定要設(shè)置給系統(tǒng)留出緩沖空間避免磁盤被寫滿導(dǎo)致節(jié)點(diǎn)不可用。dfs.datanode.max.transfer.threads根據(jù)集群并發(fā)量調(diào)整高并發(fā)場(chǎng)景適當(dāng)調(diào)大。超時(shí)參數(shù)要基于實(shí)測(cè)延遲設(shè)置不要照搬默認(rèn)值。定期 review 配置集群規(guī)模變化后原來(lái)的參數(shù)可能就不合適了。6.3 定期做健康檢查我習(xí)慣每周做一次集群健康檢查包括磁盤健康、網(wǎng)絡(luò)質(zhì)量、關(guān)鍵指標(biāo)趨勢(shì)、報(bào)錯(cuò)日志統(tǒng)計(jì)。這個(gè)習(xí)慣幫我提前發(fā)現(xiàn)過(guò)好幾次潛在問(wèn)題比如某塊盤的 SMART 指標(biāo)在惡化、某個(gè)機(jī)架的網(wǎng)卡錯(cuò)誤計(jì)數(shù)在增長(zhǎng)。健康檢查不需要很復(fù)雜寫個(gè)腳本把關(guān)鍵命令跑一遍輸出一份報(bào)告就行。關(guān)鍵是堅(jiān)持做并且對(duì)異常項(xiàng)跟進(jìn)處理。7. 寫在最后關(guān)于這個(gè)報(bào)錯(cuò)的一點(diǎn)個(gè)人體會(huì)處理了這么多次WRITE_BLOCK失敗我最大的體會(huì)是不要被報(bào)錯(cuò)的字面意思帶偏。它只是一個(gè)信號(hào)告訴你寫塊這件事出問(wèn)題了但具體是什么問(wèn)題必須靠完整的堆棧和系統(tǒng)性的排查來(lái)確定。另一個(gè)體會(huì)是很多看似突發(fā)的故障其實(shí)早有征兆。磁盤使用率緩慢上升、GC 停頓逐漸變長(zhǎng)、網(wǎng)絡(luò)重傳率悄悄升高這些都是預(yù)警信號(hào)。如果平時(shí)有監(jiān)控和健康檢查的習(xí)慣就能在問(wèn)題爆發(fā)前處理掉而不是等到凌晨被叫起來(lái)救火。最后分享一個(gè)小技巧建立一個(gè)故障-根因-處理的對(duì)照表每次處理完問(wèn)題就更新進(jìn)去。時(shí)間長(zhǎng)了這張表就是你自己集群的專屬排查手冊(cè)比任何通用文檔都好用。因?yàn)槊總€(gè)集群的硬件、網(wǎng)絡(luò)、業(yè)務(wù)負(fù)載都不一樣只有自己積累的經(jīng)驗(yàn)才最貼合實(shí)際。如果你正在被這個(gè)報(bào)錯(cuò)困擾希望這篇內(nèi)容能幫你理清思路。排查的過(guò)程可能有點(diǎn)繁瑣但只要按鏈路一段段驗(yàn)證總能找到根因。