據(jù)服務(wù)監(jiān)控運(yùn)維實(shí)戰(zhàn):從指標(biāo)體系到告警治理與故障排查)
周末凌晨?jī)牲c(diǎn)手機(jī)震了。第一反應(yīng)是“數(shù)據(jù)服務(wù)掛了”。打開(kāi)電腦看了下果然某張核心報(bào)表的數(shù)據(jù)產(chǎn)出時(shí)間已經(jīng)超過(guò)SLA兩小時(shí)下游三個(gè)業(yè)務(wù)方連著發(fā)來(lái)問(wèn)詢。這種場(chǎng)景做過(guò)大數(shù)據(jù)運(yùn)維的人都不會(huì)陌生。數(shù)據(jù)服務(wù)的監(jiān)控與運(yùn)維平時(shí)看著不起眼一出問(wèn)題就是大事。我寫這篇東西是把這幾年在“大數(shù)據(jù)數(shù)據(jù)服務(wù)監(jiān)控與運(yùn)維”上踩過(guò)的坑、總結(jié)出來(lái)的套路整體梳理一遍。不是講某個(gè)具體平臺(tái)怎么用而是講清楚一套從指標(biāo)設(shè)計(jì)、監(jiān)控搭建、告警治理到故障排查、日常運(yùn)維的完整方法論。適合剛接手?jǐn)?shù)據(jù)平臺(tái)的同學(xué)也適合已經(jīng)寫了幾年監(jiān)控規(guī)則但總覺(jué)得“告警一堆、有效沒(méi)幾個(gè)”的團(tuán)隊(duì)參考。你不需要照著某個(gè)工具一步步操作但看完應(yīng)該能知道自己團(tuán)隊(duì)缺什么、該補(bǔ)什么、為什么那么做。1. 先搞清楚數(shù)據(jù)服務(wù)監(jiān)控運(yùn)維到底在管什么1.1 數(shù)據(jù)服務(wù)不等于數(shù)據(jù)平臺(tái)很多團(tuán)隊(duì)把“大數(shù)據(jù)運(yùn)維”等同于“看著HDFS容量、YARN資源、節(jié)點(diǎn)心跳”這個(gè)認(rèn)知在早期沒(méi)問(wèn)題但一旦數(shù)據(jù)開(kāi)始對(duì)外提供服務(wù)監(jiān)控的視角就完全不一樣了。數(shù)據(jù)服務(wù)這個(gè)概念往寬了說(shuō)包括對(duì)外提供查詢的API接口比如訂單查詢、用戶畫像查詢支撐BI報(bào)表的離線表與實(shí)時(shí)表比如經(jīng)營(yíng)看板、大屏展示定時(shí)或?qū)崟r(shí)的數(shù)據(jù)同步任務(wù)比如從業(yè)務(wù)庫(kù)同步到數(shù)倉(cāng)、從數(shù)倉(cāng)導(dǎo)出到業(yè)務(wù)系統(tǒng)數(shù)據(jù)推送服務(wù)指把計(jì)算結(jié)果推送到下游消息隊(duì)列或業(yè)務(wù)數(shù)據(jù)庫(kù)。這些服務(wù)共同的特點(diǎn)是它們直接面對(duì)業(yè)務(wù)方有明確的SLA要求出問(wèn)題會(huì)立刻被感知。而數(shù)據(jù)平臺(tái)本身Hadoop、Spark、Flink、Kafka這些只是支撐這些服務(wù)的底層設(shè)施。所以監(jiān)控運(yùn)維的對(duì)象要分兩層看底層是平臺(tái)與任務(wù)上層是服務(wù)與數(shù)據(jù)。底層掛了未必影響業(yè)務(wù)但數(shù)據(jù)服務(wù)的可用性和數(shù)據(jù)質(zhì)量出問(wèn)題那就是事故。反過(guò)來(lái)底層沒(méi)掛但數(shù)據(jù)沒(méi)產(chǎn)出一樣是事故。這就是為什么很多團(tuán)隊(duì)“監(jiān)控很全、告警很多”卻依然出事——監(jiān)控對(duì)象選錯(cuò)了全監(jiān)控的是底層上層的數(shù)據(jù)產(chǎn)出和質(zhì)量反而沒(méi)人盯。1.2 監(jiān)控與運(yùn)維的兩個(gè)真實(shí)目標(biāo)把目標(biāo)說(shuō)清楚后面所有設(shè)計(jì)才有依據(jù)。我總結(jié)下來(lái)就兩條第一保證數(shù)據(jù)“按時(shí)、按質(zhì)、可用”。“按時(shí)”指數(shù)據(jù)產(chǎn)出時(shí)間要滿足SLA比如每天8點(diǎn)前今天的報(bào)表必須能查到“按質(zhì)”指數(shù)據(jù)是對(duì)的不能出現(xiàn)空值、重復(fù)、明顯波動(dòng)異常“可用”指查詢服務(wù)不掛接口響應(yīng)在合理范圍內(nèi)。**第二故障時(shí)能快速定位、快速恢復(fù)。**沒(méi)有什么監(jiān)控能保證不出故障監(jiān)控的價(jià)值在于出問(wèn)題時(shí)盡可能縮小排查范圍減少?gòu)摹皥?bào)警”到“找到根因”的時(shí)間。理想狀態(tài)是告警里直接告訴你是哪個(gè)任務(wù)、哪個(gè)分區(qū)、哪個(gè)環(huán)節(jié)出了問(wèn)題而不是讓你對(duì)著幾十臺(tái)機(jī)器挨個(gè)翻日志。這兩條目標(biāo)決定了監(jiān)控設(shè)計(jì)的優(yōu)先級(jí)。第一優(yōu)先級(jí)永遠(yuǎn)是數(shù)據(jù)產(chǎn)出鏈路本身也就是調(diào)度、任務(wù)、數(shù)據(jù)分區(qū)、表新鮮度。第二優(yōu)先級(jí)才是機(jī)器資源、組件狀態(tài)。別把順序搞反了。注意這里說(shuō)的“數(shù)據(jù)質(zhì)量”不是BI分析里數(shù)據(jù)質(zhì)量治理那么大而全的概念而是運(yùn)維視角下最基本的數(shù)據(jù)正確性保障比如關(guān)鍵字段不能為空、主鍵不能重復(fù)、數(shù)值波動(dòng)不能異常。這兩者覆蓋范圍有重疊但實(shí)踐上完全不是一個(gè)團(tuán)隊(duì)在推動(dòng)。2. 監(jiān)控指標(biāo)體系怎么搭才算完整2.1 從用戶視角倒推服務(wù)可用性與數(shù)據(jù)新鮮度設(shè)計(jì)監(jiān)控指標(biāo)最常見(jiàn)的錯(cuò)誤是“有什么監(jiān)控什么”——內(nèi)存、CPU、磁盤用滿了就報(bào)警聽(tīng)起來(lái)很穩(wěn)但業(yè)務(wù)方根本不關(guān)心你磁盤剩多少他們只關(guān)心“報(bào)表能不能查到”“接口返回正不正?!?。所以我的做法是反著來(lái)先問(wèn)業(yè)務(wù)方感知到什么才算“好”匯總下來(lái)就三個(gè)詞查得到、出得快、數(shù)據(jù)對(duì)。對(duì)應(yīng)的指標(biāo)是查詢成功率單位時(shí)間內(nèi)數(shù)據(jù)服務(wù)接口或報(bào)表查詢的成功次數(shù)占總請(qǐng)求次數(shù)的比例。一般要求99.9%以上低于99.5%就需要關(guān)注查詢響應(yīng)時(shí)間用TP99而不是平均值。平均值最容易被極端值拉高或拉低TP99才能反映絕大多數(shù)用戶體驗(yàn)數(shù)據(jù)新鮮度指的是數(shù)據(jù)產(chǎn)出時(shí)間與業(yè)務(wù)時(shí)間的差距。小時(shí)級(jí)任務(wù)看分鐘級(jí)延遲天級(jí)任務(wù)看產(chǎn)出時(shí)間點(diǎn)是否晚于SLA約定時(shí)間數(shù)據(jù)產(chǎn)出完整性今天的分區(qū)是否齊全表行數(shù)與昨日對(duì)比是否異常波動(dòng)。換個(gè)角度看業(yè)務(wù)方感知到“服務(wù)掛了”往往是間接的——他們查不到數(shù)據(jù)或者打開(kāi)報(bào)表看到“暫無(wú)數(shù)據(jù)”。而底層的表現(xiàn)可能是某個(gè)任務(wù)失敗重試后成功了或者調(diào)度隊(duì)列里積壓了任務(wù)或者某個(gè)分區(qū)遲遲沒(méi)有生成。監(jiān)控體系設(shè)計(jì)的第一原則就是從用戶可感知的問(wèn)題出發(fā)向下拆解到具體可定位的監(jiān)控點(diǎn)。2.2 系統(tǒng)資源與任務(wù)運(yùn)行的雙層指標(biāo)有了用戶視角的指標(biāo)還需要一層支撐性的指標(biāo)池。我習(xí)慣分成三個(gè)層級(jí)層級(jí)典型指標(biāo)作用服務(wù)層接口成功率、調(diào)用量、TP99、數(shù)據(jù)新鮮度反映用戶實(shí)際體驗(yàn)是告警的第一觸發(fā)點(diǎn)任務(wù)層調(diào)度成功率、任務(wù)耗時(shí)、重試次數(shù)、失敗原因、Checkpoint狀態(tài)快速定位是哪個(gè)數(shù)據(jù)加工環(huán)節(jié)出了問(wèn)題資源層CPU、內(nèi)存、磁盤IO、GC時(shí)間、連接數(shù)、隊(duì)列積壓提供根因線索一般不直接告警業(yè)務(wù)方為什么要分三層因?yàn)楦婢仨殢姆?wù)層往下穿透。比如“報(bào)表查不到”這個(gè)服務(wù)層告警觸發(fā)了值班同學(xué)需要一層層往下看先看數(shù)據(jù)更新任務(wù)是否成功任務(wù)層不成功再看任務(wù)所在機(jī)器資源是否異常資源層資源沒(méi)問(wèn)題再看日志具體報(bào)錯(cuò)。這個(gè)順序就是標(biāo)準(zhǔn)的定位路徑。在這三層之上實(shí)時(shí)鏈路還要單獨(dú)補(bǔ)充幾個(gè)指標(biāo)消費(fèi)延遲消費(fèi)者處理到的最新消息時(shí)間與最新生產(chǎn)消息時(shí)間之差單位毫秒。實(shí)時(shí)鏈路85%的故障都表現(xiàn)在這個(gè)指標(biāo)上消息積壓量Topic或ConsumerGroup中未消費(fèi)的消息數(shù)Checkpoint失敗次數(shù)與耗時(shí)Flink任務(wù)健康度的晴雨表連續(xù)多次Checkpoint失敗基本意味著任務(wù)即將重啟。我見(jiàn)過(guò)不少團(tuán)隊(duì)實(shí)時(shí)鏈路掛了半小時(shí)告警是“Kafka消費(fèi)者線程數(shù)下降”這種告警太底層了等值班同學(xué)反應(yīng)過(guò)來(lái)業(yè)務(wù)方已經(jīng)排隊(duì)來(lái)問(wèn)了。直接監(jiān)控“消費(fèi)延遲”和“負(fù)投產(chǎn)周期”這類服務(wù)層指標(biāo)才是有效的方式。2.3 閾值怎么定從靜態(tài)閾值到動(dòng)態(tài)基線指標(biāo)有了閾值怎么定這是監(jiān)控體系里爭(zhēng)議最多的地方。拍腦袋定一個(gè)“CPU超過(guò)80%報(bào)警”的規(guī)則實(shí)際運(yùn)行中你會(huì)發(fā)現(xiàn)兩種問(wèn)題一種是CPU長(zhǎng)期維持在85%但業(yè)務(wù)完全正常告警發(fā)多了沒(méi)人看另一種是內(nèi)存從2G漲到4G雖然絕對(duì)值不高但已經(jīng)翻倍靜態(tài)閾值根本不會(huì)觸發(fā)——結(jié)果OOM了才發(fā)現(xiàn)。我的經(jīng)驗(yàn)是分三步走**第一步先按經(jīng)驗(yàn)定靜態(tài)保守閾值。**比如接口成功率低于99.5%告警、消費(fèi)延遲超過(guò)5分鐘告警、存儲(chǔ)空間使用率超過(guò)85%告警。這些值不用太準(zhǔn)目的是兜底防止“什么都沒(méi)監(jiān)控”的空白期。**第二步觀察2到4周用歷史數(shù)據(jù)校準(zhǔn)。**把監(jiān)控指標(biāo)保存下來(lái)看指標(biāo)在正常周期內(nèi)的波動(dòng)范圍和基線。比如接口調(diào)用量每天早高峰是低峰的10倍晚高峰TP99天然比白天高那閾值就必須按不同時(shí)段分別設(shè)定。**第三步引入動(dòng)態(tài)基線檢測(cè)。**正經(jīng)的做法是基于時(shí)間序列做周期性預(yù)測(cè)比如歷史30天同周期數(shù)據(jù)做滑動(dòng)平均當(dāng)前值與預(yù)測(cè)值偏差超過(guò)一定倍數(shù)比如3倍標(biāo)準(zhǔn)差或50%偏差才告警。這樣既能捕捉“絕對(duì)值不大但趨勢(shì)異?!钡膯?wèn)題也能減少靜態(tài)閾值導(dǎo)致的誤報(bào)。提示動(dòng)態(tài)基線不是越復(fù)雜越好。剛開(kāi)始做用“同比昨天的同一時(shí)刻、環(huán)比上周同一天”這兩個(gè)維度做簡(jiǎn)單的偏差檢測(cè)準(zhǔn)確率已經(jīng)相當(dāng)高了。直接上機(jī)器學(xué)習(xí)模型反而會(huì)因?yàn)闃颖静蛔愫吞卣麟s亂搞出更多誤報(bào)。2.4 告警分級(jí)不區(qū)分級(jí)別的告警等于沒(méi)告警最后再說(shuō)告警分級(jí)。沒(méi)有分級(jí)的告警體系值班同學(xué)會(huì)被拖垮。我的團(tuán)隊(duì)把告警分成三級(jí)級(jí)別定義響應(yīng)要求通知方式P1核心服務(wù)不可用影響面覆蓋多個(gè)業(yè)務(wù)方或核心報(bào)表立即響應(yīng)15分鐘內(nèi)介入電話短信群所有人P2非核心服務(wù)異常單一任務(wù)失敗影響單業(yè)務(wù)方30分鐘內(nèi)響應(yīng)工作時(shí)間立即處理短信群消息P3潛在風(fēng)險(xiǎn)資源水位偏高任務(wù)重試成功當(dāng)天處理值班同學(xué)視情況處理群消息靜默通知次日跟進(jìn)P1一定是服務(wù)層指標(biāo)觸發(fā)的不允許出現(xiàn)“資源層指標(biāo)直接報(bào)P1”的情況——除非你已經(jīng)確認(rèn)資源問(wèn)題正在壓垮業(yè)務(wù)。分級(jí)規(guī)則寫進(jìn)告警引擎配置里而不是靠值班同學(xué)自己判斷這很重要。3. 監(jiān)控工具選型與告警體系搭建3.1 開(kāi)源監(jiān)控棧從指標(biāo)采集到告警觸達(dá)工具選型上大多數(shù)團(tuán)隊(duì)會(huì)走同一條路先用開(kāi)源組合搭起一套能用的體系跑一段時(shí)間后再?zèng)Q定要不要自研。這個(gè)路線沒(méi)問(wèn)題我建議的黃金組合是指標(biāo)采集與存儲(chǔ)Prometheus 各類Exporter。Prometheus生態(tài)對(duì)大數(shù)據(jù)組件非常友好Node Exporter看機(jī)器指標(biāo)JMX Exporter看Java進(jìn)程還有現(xiàn)成的Kafka Exporter、Flink Exporter。配置不算復(fù)雜收益立竿見(jiàn)影可視化Grafana。主要的用途不是做漂亮的大屏而是把“服務(wù)層指標(biāo)任務(wù)層指標(biāo)資源層指標(biāo)”放在同一張圖里故障定位時(shí)一眼看到全鏈路狀態(tài)告警引擎AlertManager。負(fù)責(zé)把Prometheus的告警規(guī)則按照分組、抑制、靜默策略發(fā)送出去同時(shí)做好路由讓告警只發(fā)到該看的人日志聚合主流的日志平臺(tái)方案或者輕量級(jí)的 Loki。日志平臺(tái)吃資源但大數(shù)據(jù)場(chǎng)景排查問(wèn)題離不開(kāi)全文檢索和上下文日志這一塊至少要有一套任務(wù)調(diào)度監(jiān)控針對(duì)實(shí)際使用的調(diào)度平臺(tái)或自研監(jiān)控腳本。核心是拿到每個(gè)任務(wù)的狀態(tài)、耗時(shí)、失敗原因。這套組合完整跑通之后大概能覆蓋80%的監(jiān)控需求。剩下的20%需求比如自定義數(shù)據(jù)質(zhì)量校驗(yàn)、全鏈路血緣告警往往需要結(jié)合自己的數(shù)據(jù)平臺(tái)現(xiàn)狀寫一些腳本服務(wù)。不要一開(kāi)始就追求自研統(tǒng)一監(jiān)控平臺(tái)那是個(gè)無(wú)底洞。先把開(kāi)源工具用好讓數(shù)據(jù)沉淀下來(lái)后面整理成平臺(tái)才有依據(jù)。3.2 主動(dòng)撥測(cè)與被動(dòng)監(jiān)控相結(jié)合被動(dòng)監(jiān)控指的是數(shù)據(jù)服務(wù)被調(diào)用時(shí)產(chǎn)生的指標(biāo)比如接口成功率、響應(yīng)耗時(shí)。被動(dòng)監(jiān)控有個(gè)盲區(qū)如果沒(méi)人調(diào)用接口掛了也不知道。所以必須有主動(dòng)探測(cè)來(lái)兜底。主動(dòng)探測(cè)分兩種形態(tài)第一種是黑盒撥測(cè)。用一個(gè)獨(dú)立的探測(cè)程序不依賴業(yè)務(wù)服務(wù)的代碼定時(shí)模擬用戶行為比如每小時(shí)調(diào)用一次核心查詢API、每5分鐘請(qǐng)求一次報(bào)表數(shù)據(jù)接口檢查返回狀態(tài)碼、響應(yīng)耗時(shí)和結(jié)果內(nèi)容。一旦連續(xù)失敗N次直接報(bào)P1。這相當(dāng)于給服務(wù)層指標(biāo)加了一份“體外保險(xiǎn)”尤其適合核心鏈路。第二種是數(shù)據(jù)質(zhì)量探針。在數(shù)據(jù)產(chǎn)出后通過(guò)SQL或腳本掃描目標(biāo)表的關(guān)鍵規(guī)則比如主鍵是否重復(fù)關(guān)鍵字段空值率是否超過(guò)閾值關(guān)鍵指標(biāo)的今日值與歷史同期相比是否有異常波動(dòng)分區(qū)數(shù)據(jù)量是否滿足最小行數(shù)要求。探針結(jié)果可以寫成自定義指標(biāo)發(fā)到Prometheus再走告警體系。這樣就能監(jiān)控到“數(shù)據(jù)雖然產(chǎn)出了但數(shù)據(jù)本身有問(wèn)題”這種最隱蔽的事故。我在實(shí)際落地時(shí)通常的做法是每天數(shù)據(jù)產(chǎn)出后半小時(shí)對(duì)核心報(bào)表表跑一組完整性校驗(yàn)。AI場(chǎng)景下單表數(shù)據(jù)量減少30%以上直接觸發(fā)P2告警。這套機(jī)制已經(jīng)幫我們提前攔截過(guò)好幾次“上游同步漏數(shù)據(jù)”的問(wèn)題。3.3 告警通知與值班流程的銜接告警發(fā)出去只是開(kāi)始真正的閉環(huán)是要有人響應(yīng)、有人處理、有人跟進(jìn)。這個(gè)銜接環(huán)節(jié)掉鏈子比監(jiān)控缺失更嚴(yán)重。我建議先設(shè)定幾個(gè)簡(jiǎn)單規(guī)則認(rèn)領(lǐng)機(jī)制群里收到告警后必須有人回復(fù)“處理中”否則定時(shí)器會(huì)在5分鐘后再次提醒15分鐘后仍未認(rèn)領(lǐng)則自動(dòng)通過(guò)電話通知當(dāng)班值班人升級(jí)機(jī)制P1告警15分鐘內(nèi)無(wú)人有效處理升級(jí)到值班主管30分鐘內(nèi)升級(jí)到團(tuán)隊(duì)負(fù)責(zé)人保證緊急時(shí)有人拍板而不是大家集體沉默恢復(fù)確認(rèn)告警恢復(fù)后不能直接關(guān)閉還要等待至少10分鐘觀察期確認(rèn)服務(wù)穩(wěn)定、數(shù)據(jù)補(bǔ)跑成功才算真正閉環(huán)每日告警回顧第二天早上花10分鐘過(guò)前一天的告警記錄分一下類有效告警、誤報(bào)、可避免告警。這個(gè)動(dòng)作看著簡(jiǎn)單卻是整個(gè)告警體系優(yōu)化的關(guān)鍵數(shù)據(jù)來(lái)源。認(rèn)領(lǐng)和升級(jí)機(jī)制可以通過(guò)企業(yè)微信或釘釘機(jī)器人配合簡(jiǎn)單的后端邏輯實(shí)現(xiàn)也可以直接用現(xiàn)成的告警協(xié)同平臺(tái)。核心是讓人知道“這條告警現(xiàn)在到底有沒(méi)有人管”而不是發(fā)了就完事。4. 常見(jiàn)故障排查與實(shí)戰(zhàn)記錄4.1 數(shù)據(jù)延遲類故障任務(wù)顯示成功但數(shù)據(jù)就是沒(méi)出來(lái)數(shù)據(jù)延遲是數(shù)據(jù)服務(wù)運(yùn)維里出現(xiàn)概率最高的一類問(wèn)題。它最讓人頭疼的地方在于很多情況下任務(wù)沒(méi)有失敗狀態(tài)顯示“成功”但下游就是查不到新數(shù)據(jù)。我遇到過(guò)一次典型的案例。某核心離線任務(wù)每天凌晨2點(diǎn)調(diào)度運(yùn)行時(shí)長(zhǎng)一般40分鐘有一天早上到點(diǎn)后下游報(bào)表沒(méi)有更新。檢查調(diào)度平臺(tái)任務(wù)狀態(tài)是成功的查看任務(wù)日志最后幾行沒(méi)有明顯報(bào)錯(cuò)。問(wèn)題出在哪兒后來(lái)按這條路徑找到根因先看任務(wù)運(yùn)行時(shí)長(zhǎng)曲線發(fā)現(xiàn)當(dāng)天運(yùn)行時(shí)間比平常多了一個(gè)半小時(shí)再看具體的階段耗時(shí)定位到某個(gè)數(shù)據(jù)清洗SQL的reduce階段異常緩慢。進(jìn)入檢查模式后發(fā)現(xiàn)某個(gè)上游表在當(dāng)天產(chǎn)生了大量重復(fù)數(shù)據(jù)導(dǎo)致join的中間結(jié)果膨脹了一百多倍。任務(wù)雖然跑完了但因?yàn)檫\(yùn)行超時(shí)數(shù)據(jù)寫入分區(qū)的時(shí)間晚于下游報(bào)表的讀取時(shí)機(jī)報(bào)表任務(wù)沒(méi)有讀取到最新分區(qū)。這個(gè)案例能給幾個(gè)排查套路這類定位思路最早來(lái)自對(duì)“調(diào)度、計(jì)算、寫入”三個(gè)環(huán)節(jié)的逐一排查遇到延遲問(wèn)題不要只盯任務(wù)是否成功還要關(guān)注運(yùn)行時(shí)長(zhǎng)曲線有沒(méi)有異常。定期繪制任務(wù)運(yùn)行時(shí)長(zhǎng)曲線能幫你一眼看出“今天慢”是偶發(fā)問(wèn)題還是趨勢(shì)性問(wèn)題。**第二步通過(guò)數(shù)據(jù)血緣或任務(wù)依賴關(guān)系向下游擴(kuò)散查詢。**比如從報(bào)表往前回溯上游表是哪個(gè)任務(wù)產(chǎn)出的那個(gè)任務(wù)的調(diào)度時(shí)間是否正常。大數(shù)據(jù)平臺(tái)的血緣關(guān)系在這一刻的價(jià)值真的比任何監(jiān)控面板都大。**第三步看運(yùn)行日志和資源監(jiān)控的交叉點(diǎn)。**如果任務(wù)慢是因?yàn)橘Y源競(jìng)爭(zhēng)——同隊(duì)列的另一個(gè)大任務(wù)搶占了CPU或內(nèi)存——資源監(jiān)控里會(huì)看到明顯的資源水位上升這時(shí)候直接去調(diào)隊(duì)列配置比優(yōu)化代碼要快得多。4.2 服務(wù)OOM與GC問(wèn)題接口突然變慢隨后開(kāi)始報(bào)錯(cuò)數(shù)據(jù)服務(wù)的實(shí)時(shí)查詢進(jìn)程出現(xiàn)內(nèi)存問(wèn)題也很常見(jiàn)?,F(xiàn)象是接口從“偶爾慢”到“頻繁超時(shí)”再到“開(kāi)始返回500”。排查思路要形成肌肉記憶先看監(jiān)控面板的JVM內(nèi)存曲線和GC頻率再分析堆內(nèi)存中緩存的數(shù)據(jù)結(jié)構(gòu)。我遇到過(guò)的一個(gè)案例是某個(gè)服務(wù)為了提升查詢性能啟動(dòng)時(shí)把一張配置表全量加載到內(nèi)存里。平時(shí)這張表只有幾萬(wàn)行完全沒(méi)問(wèn)題。后來(lái)上游數(shù)據(jù)量增長(zhǎng)這張表一天之內(nèi)漲到了幾百萬(wàn)行服務(wù)啟動(dòng)加載時(shí)直接把堆內(nèi)存撐爆真正可怕的還是區(qū)間峰值——在數(shù)據(jù)量增長(zhǎng)的過(guò)程中好幾次GC把偶發(fā)流量頂住了看著沒(méi)掛但響應(yīng)時(shí)間已經(jīng)劣化了三四倍。生產(chǎn)上到中午流量高峰直接OOM。這類問(wèn)題的排查有幾個(gè)關(guān)鍵點(diǎn)看GC日志是最直接的。通過(guò)GCViewer這類工具分析回收類型和頻率可以基本確定是“內(nèi)存分配過(guò)快”還是“存在大對(duì)象堆積”?!癎C較為頻繁但整體內(nèi)存曲線平緩”和“內(nèi)存曲線持續(xù)爬升、回收后回落不明顯”分別對(duì)應(yīng)兩種不同方向做堆轉(zhuǎn)儲(chǔ)快照Heap Dump分析可以搭配內(nèi)存分析工具查看大對(duì)象分布確認(rèn)是否有過(guò)量緩存或數(shù)據(jù)集合沒(méi)有得到釋放看監(jiān)控中的線程池排隊(duì)情況如果接口線程池滿請(qǐng)求會(huì)長(zhǎng)期堆積最終觸發(fā)超時(shí)——這個(gè)現(xiàn)象也經(jīng)常被誤判為“服務(wù)負(fù)載高”實(shí)際是內(nèi)存問(wèn)題間接拖累了線程處理。經(jīng)驗(yàn)給查詢服務(wù)加內(nèi)存緩存時(shí)必須設(shè)置最大容量上限和過(guò)期時(shí)間絕對(duì)不能“無(wú)界緩存”。數(shù)據(jù)量不可控是常態(tài)如果你不限制緩存緩存遲早會(huì)限制你。4.3 數(shù)據(jù)質(zhì)量異常監(jiān)控怎么發(fā)現(xiàn)“數(shù)據(jù)不對(duì)勁”還有一種故障最難防服務(wù)沒(méi)掛、任務(wù)沒(méi)失敗、數(shù)據(jù)也產(chǎn)出了但數(shù)據(jù)本身是錯(cuò)的。比如某報(bào)表今天銷量比昨天低了60%某張用戶表出現(xiàn)了大量負(fù)數(shù)某個(gè)維度的匯總值比前一天翻了好幾倍。這些問(wèn)題的共性在于從系統(tǒng)和任務(wù)指標(biāo)上完全看不出來(lái)必須靠數(shù)據(jù)內(nèi)容本身的校驗(yàn)。我的做法是建立一張“核心數(shù)據(jù)質(zhì)量規(guī)則表”對(duì)最重要的幾十張表配置規(guī)則。每張表至少覆蓋四類檢查檢查類型規(guī)則示例告警級(jí)別完整性今日分區(qū)行數(shù)不低于昨日50%不高于昨日200%P2唯一性主鍵重復(fù)數(shù)為0P2有效性金額字段不允許負(fù)數(shù)狀態(tài)字段必須在約定枚舉值內(nèi)P3波動(dòng)性核心指標(biāo)日環(huán)比變化不超過(guò)30%業(yè)務(wù)波動(dòng)大時(shí)可放寬到50%P2還有一種常見(jiàn)情況是上游同步延遲導(dǎo)致“數(shù)據(jù)補(bǔ)寫”——今天的分區(qū)一開(kāi)始沒(méi)數(shù)據(jù)幾小時(shí)后才補(bǔ)上。你的檢查任務(wù)如果是數(shù)據(jù)產(chǎn)出半小時(shí)后跑的很可能誤報(bào)。所以質(zhì)量探測(cè)任務(wù)必須和調(diào)度SLA對(duì)齊要么在SLA時(shí)間之后運(yùn)行要么在規(guī)則里跳過(guò)“未產(chǎn)出分區(qū)”的情況。我踩過(guò)的一個(gè)坑規(guī)則配好了但只用一個(gè)固定閾值“環(huán)比波動(dòng)不能超過(guò)30%”。某天上線了大促活動(dòng)銷量直接從5000漲到30000規(guī)則立刻誤報(bào)。后來(lái)改成“周日與上周日對(duì)比、工作日與昨日對(duì)比”這類更貼合業(yè)務(wù)周期的規(guī)則誤報(bào)率才降下來(lái)。做數(shù)據(jù)質(zhì)量規(guī)則天然地要理解業(yè)務(wù)節(jié)奏這是繞不過(guò)去的。4.4 慢查詢與性能瓶頸API服務(wù)變慢的排查路徑數(shù)據(jù)服務(wù)接口變慢是另一類高頻問(wèn)題?,F(xiàn)象清晰但根因往往五花八門。排查時(shí)建議按這個(gè)順序快速排除先看數(shù)據(jù)庫(kù)或OLAP引擎?zhèn)鹊穆樵?。大多?shù)“接口慢”本質(zhì)是“查詢慢”把服務(wù)端的慢查詢?nèi)罩敬蜷_(kāi)找到耗時(shí)最高的SQL看執(zhí)行計(jì)劃是否合理、是否缺少分區(qū)裁剪、是否在大表上做了無(wú)過(guò)濾條件的全表掃描再看服務(wù)端是否有跨服務(wù)調(diào)用比如API接口內(nèi)部還依賴另一個(gè)用戶系統(tǒng)或數(shù)據(jù)服務(wù)。鏈路追蹤里看下游調(diào)用耗時(shí)占比如果有外部調(diào)用占比極高問(wèn)題大概率在下游曾經(jīng)排查過(guò)一個(gè)“接口偶爾超時(shí)”的工單最后定位到原因是該接口內(nèi)部調(diào)用的下游服務(wù)每10分鐘觸發(fā)一次Full GC那段時(shí)間接口響應(yīng)就變慢全鏈路追蹤的耗時(shí)分析幫了大忙查緩存是否生效。如果命中率低于90%你可能需要調(diào)整緩存key的設(shè)計(jì)或緩存粒度的策略最后看是否出現(xiàn)“熱點(diǎn)查詢”或“大查詢互斥”。數(shù)據(jù)服務(wù)場(chǎng)景里高并發(fā)下某些大查詢會(huì)互相搶占CPU和IO導(dǎo)致所有查詢集體退化。這時(shí)優(yōu)先做的是資源隊(duì)列隔離把大查詢和小查詢分開(kāi)。**分級(jí)響應(yīng)**在壓測(cè)階段就把大查詢和小查詢分配到不同資源隊(duì)列是一種性價(jià)比很高的容量治理手段能在流量高峰期避免“一條大查詢拖垮全鏈路”的情況。5. 日常運(yùn)維規(guī)范與自動(dòng)化實(shí)踐5.1 變更管理大多數(shù)故障的根源是“改動(dòng)了什么”如果統(tǒng)計(jì)故障來(lái)源“變更”會(huì)排在第一位不管是配置修改、版本升級(jí)還是表結(jié)構(gòu)調(diào)整。數(shù)據(jù)服務(wù)的運(yùn)維要做到“變更可追蹤、發(fā)布可回滾”。我的團(tuán)隊(duì)內(nèi)部有一套簡(jiǎn)單但有效的變更規(guī)范變更窗口核心鏈路的變更集中在每周固定的時(shí)間窗口比如周二和周四下午窗口內(nèi)禁止隨意發(fā)布窗口外有緊急發(fā)布需求必須經(jīng)過(guò)審批灰度發(fā)布新版本先發(fā)布到單臺(tái)實(shí)例或給部分流量比如先切5%的流量觀察10分鐘核心指標(biāo)無(wú)異常后逐步放量全量發(fā)布前不允許直接替換所有節(jié)點(diǎn)表結(jié)構(gòu)變更上線前必須跑兼容性檢查確認(rèn)下游查詢SQL不依賴被刪除的字段避免上游刪列后下游任務(wù)大面積失敗。表字段修改是數(shù)據(jù)服務(wù)變更里最容易“踩雷”的回滾預(yù)案每次變更前必須明確回滾方案比如配置項(xiàng)的舊值備份、版本的保留、數(shù)據(jù)同步任務(wù)的重跑策略。沒(méi)有回滾預(yù)案的變更等到出問(wèn)題時(shí)現(xiàn)場(chǎng)才想方案代價(jià)極其昂貴。這些規(guī)范聽(tīng)起來(lái)都是常識(shí)但執(zhí)行起來(lái)最難的是“堅(jiān)持”。團(tuán)隊(duì)里總會(huì)有聲音說(shuō)“這個(gè)改動(dòng)很小不用走流程”而絕大多數(shù)事故就出在這種地方。我的態(tài)度就一條沒(méi)有記錄就沒(méi)有變更沒(méi)有回滾方案的變更不允許執(zhí)行。5.2 容量管理與成本優(yōu)化別等磁盤滿了才行動(dòng)容量問(wèn)題不像故障那么緊急但每個(gè)月都會(huì)來(lái)找你。存儲(chǔ)滿了、任務(wù)隊(duì)列積壓、成本超預(yù)算這些都是運(yùn)維團(tuán)隊(duì)日常要處理的“大問(wèn)題”。存儲(chǔ)治理方面最有效的四板斧冷熱分層把超過(guò)一定時(shí)間未被訪問(wèn)的數(shù)據(jù)移到冷存儲(chǔ)查詢不常用這是性價(jià)比最高的一步TTL生命周期管理給ODS層明細(xì)數(shù)據(jù)設(shè)置明確的保留周期默認(rèn)情況滾動(dòng)保留有特殊需求再單獨(dú)申請(qǐng)延長(zhǎng)定期清理臨時(shí)表和后綴表很多任務(wù)運(yùn)行過(guò)程中會(huì)生成中間表任務(wù)結(jié)束不清理日積月累就是幾百GB甚至TB級(jí)別的垃圾小文件治理小文件多會(huì)導(dǎo)致NameNode壓力大、查詢變慢定期對(duì)產(chǎn)生大量小文件的分區(qū)執(zhí)行合并操作。計(jì)算成本方面主要抓兩點(diǎn)一是任務(wù)運(yùn)行時(shí)長(zhǎng)TOP排名每周看一次把耗時(shí)異常的任務(wù)挑出來(lái)專項(xiàng)優(yōu)化二是空閑資源池把夜間不用的計(jì)算隊(duì)列縮容跑批高峰再擴(kuò)容。容量管理不是“爆掉再處理”而是“按水位線預(yù)警”。建議對(duì)存儲(chǔ)使用率、任務(wù)積壓數(shù)量、消費(fèi)延遲等建立趨勢(shì)監(jiān)控每周做一次容量趨勢(shì)評(píng)估提前規(guī)劃擴(kuò)容申請(qǐng)和清理任務(wù)。5.3 自動(dòng)化運(yùn)維從“人肉巡檢”到“自愈腳本”日常運(yùn)維里有大量重復(fù)勞動(dòng)檢查任務(wù)是否失敗、檢查分區(qū)是否產(chǎn)出、檢查磁盤水位、重啟掛掉的服務(wù)。這些都應(yīng)該自動(dòng)化。我先說(shuō)一個(gè)最基礎(chǔ)的巡檢腳本思路用Shell或Python都能實(shí)現(xiàn)。核心做法是把巡檢項(xiàng)寫成腳本每天定時(shí)執(zhí)行輸出結(jié)果發(fā)到群里。#!/bin/bash # 簡(jiǎn)單巡檢腳本示例檢查關(guān)鍵分區(qū)是否產(chǎn)出 TODAY$(date %Y%m%d) TABLE_PATH/user/hive/warehouse/dws_summary/ds$TODAY if [ -d $TABLE_PATH ]; then ROW_COUNT$(hive -S -e SELECT count(*) FROM dws_summary WHERE ds$TODAY) echo 分區(qū)存在行數(shù): $ROW_COUNT if [ $ROW_COUNT -lt 1000 ]; then echo 數(shù)據(jù)異常行數(shù)過(guò)少 # 發(fā)送告警到群機(jī)器人 fi else echo 分區(qū)不存在 # 發(fā)送告警 fi自動(dòng)化的更高階段是“自愈”也就是發(fā)現(xiàn)問(wèn)題后自動(dòng)處理。我看到比較值得借鑒的實(shí)踐包括任務(wù)失敗后自動(dòng)重試兩次并等待一段時(shí)間再判斷規(guī)避偶發(fā)的資源抖動(dòng)重試仍失敗再觸發(fā)人工告警服務(wù)實(shí)例異常退出后由健康檢查自動(dòng)拉起消費(fèi)延遲超過(guò)閾值時(shí)自動(dòng)對(duì)消費(fèi)任務(wù)擴(kuò)容并行度或增加Topic分區(qū)。自愈腳本能減少一些重復(fù)性值班壓力但必須設(shè)置“熔斷開(kāi)關(guān)”——自愈動(dòng)作連續(xù)失敗N次后必須停止轉(zhuǎn)入人工處理避免自愈機(jī)器人和問(wèn)題互相拉扯產(chǎn)生更大的混亂。在實(shí)際落地過(guò)程中建議從“重試機(jī)制”開(kāi)始做。任務(wù)失敗自動(dòng)重試這個(gè)改動(dòng)不大但至少能把一半的非核心告警過(guò)濾掉給值班同學(xué)贏得寶貴的處理時(shí)間。6. 值班體系與故障應(yīng)急流程6.1 故障分級(jí)和響應(yīng)機(jī)制技術(shù)工作做久了你會(huì)發(fā)現(xiàn)監(jiān)控和工具只解決“發(fā)現(xiàn)”的問(wèn)題響應(yīng)效率始終取決于流程和人的因素。值班體系設(shè)計(jì)得好不好直接影響故障時(shí)長(zhǎng)。我建議按影響面而不是技術(shù)原因來(lái)分級(jí)故障級(jí)別判定標(biāo)準(zhǔn)處理要求P0核心數(shù)據(jù)服務(wù)完全不可用影響所有業(yè)務(wù)方或涉及核心資金鏈路立即響應(yīng)故障期間全團(tuán)隊(duì)投入每30分鐘同步一次進(jìn)展P1核心服務(wù)部分不可用影響單業(yè)務(wù)方或非核心服務(wù)全掛15分鐘內(nèi)響應(yīng)持續(xù)跟進(jìn)直至恢復(fù)P2服務(wù)可用但存在異常單任務(wù)失敗、SLA延遲在2小時(shí)內(nèi)當(dāng)班處理即可工作時(shí)間內(nèi)解決P3潛在隱患不影響當(dāng)前服務(wù)記錄跟蹤定期處理值班安排上注意兩點(diǎn)主備雙人制避免單人值班睡覺(jué)或開(kāi)會(huì)時(shí)錯(cuò)過(guò)告警。主值班處理備值班兜底P0/P1升級(jí)時(shí)兩個(gè)人可以并行排查交接班清單交班時(shí)同步當(dāng)前未恢復(fù)的告警、正在處理的變更、當(dāng)天已知的異常避免“上一班沒(méi)處理完、下一班不知道”的斷檔。6.2 故障復(fù)盤復(fù)盤的價(jià)值不在追責(zé)在改進(jìn)每次P0/P1故障必須做復(fù)盤。復(fù)盤模板固定下來(lái)可以減少情緒化討論把重心放在改進(jìn)上。我的復(fù)盤模板基本包含六項(xiàng)故障時(shí)間線什么時(shí)候開(kāi)始、什么時(shí)候發(fā)現(xiàn)、什么時(shí)候定位、什么時(shí)候恢復(fù)影響面哪些服務(wù)不可用、哪些業(yè)務(wù)受影響、影響時(shí)長(zhǎng)多久直接原因根本原因是什么觸發(fā)鏈路和觸發(fā)條件是怎樣的為什么監(jiān)控沒(méi)提前發(fā)現(xiàn)這是最核心的問(wèn)題是沒(méi)配指標(biāo)還是配了沒(méi)告警還是告警發(fā)了沒(méi)人處理改進(jìn)項(xiàng)清單每條改進(jìn)必須指定負(fù)責(zé)人和完成時(shí)間經(jīng)驗(yàn)沉淀更新操作手冊(cè)、告警規(guī)則和監(jiān)控面板。復(fù)盤最忌諱的是寫成一紙檢討書把重點(diǎn)放在“誰(shuí)操作失誤”上。我更關(guān)心的是“為什么這個(gè)失誤沒(méi)有被系統(tǒng)識(shí)別和攔截”。每次復(fù)盤都應(yīng)該推動(dòng)監(jiān)控體系的進(jìn)化——下次同樣的問(wèn)題發(fā)生能否在用戶發(fā)現(xiàn)之前就觸發(fā)告警能否在告警時(shí)直接給出更精確的定位信息復(fù)盤產(chǎn)生的改進(jìn)項(xiàng)要進(jìn)入任務(wù)跟蹤列表下次復(fù)盤時(shí)先過(guò)一遍上次改進(jìn)項(xiàng)的完成情況。如果監(jiān)控系統(tǒng)上線半年、復(fù)盤做了五次但告警規(guī)則沒(méi)有任何新增說(shuō)明復(fù)盤流于形式了。寫在最后做數(shù)據(jù)服務(wù)監(jiān)控與運(yùn)維這些年我最深的體會(huì)是能用工具解決的就不要靠人盯能靠流程預(yù)防的就不要等故障發(fā)生后再補(bǔ)救。再好的監(jiān)控面板和告警規(guī)則如果不配合有效的值班響應(yīng)流程也只是“看起來(lái)專業(yè)”的擺設(shè)。反過(guò)來(lái)也成立團(tuán)隊(duì)響應(yīng)能力和故障處理素質(zhì)再高如果沒(méi)有指標(biāo)體系和數(shù)據(jù)血緣這種基礎(chǔ)設(shè)施支撐也很難做到快速定位。最后分享一個(gè)小技巧每季度統(tǒng)計(jì)一次“告警命中率”——真正有效告警占全部告警的比例。這個(gè)數(shù)字是監(jiān)控體系健康度的晴雨表如果低于30%說(shuō)明告警規(guī)則已經(jīng)把團(tuán)隊(duì)折騰得麻木了再重要的告警也會(huì)被淹沒(méi)。這時(shí)候最該做的不是加更多規(guī)則而是主動(dòng)砍掉一半誤報(bào)、合并重復(fù)告警、提高觸發(fā)門檻把告警的“信噪比”做上去。少而準(zhǔn)的告警遠(yuǎn)比多而全的告警有價(jià)值。數(shù)據(jù)服務(wù)的監(jiān)控運(yùn)維沒(méi)有終點(diǎn)它能保持穩(wěn)定靠的不是某一次大改造而是每天削減誤報(bào)、每月補(bǔ)一條有效規(guī)則、每次故障后把教訓(xùn)沉淀下來(lái)就是這樣不斷迭代。