Grafana 告警:從看見到行動

· tech

#observability#grafana#alerting

📑 目錄

這系列從第一篇就一直押著一句話——觀測的終點不是「看到」,是「行動」。前面六篇把「看到」講完了:三支柱怎麼存、怎麼查、怎麼進來。這篇補上最後那一哩、也是整個系列的 payoff——告警(Alerting):把那塊玻璃,接上人的行動。 沒有它,再漂亮的儀表板也只是等人去盯;有了它,系統壞掉的那一刻,是它來找你,不是你剛好在看。

告警規則:一條定時跑的查詢 + 一個門檻 + 一段 for

先破一個直覺:告警不是什麼特殊機制,它就是一條會自己定時跑的查詢。Grafana 的 Unified Alerting,一條 alert rule 做的事就三步——每隔一個 interval 對 data source 跑一次查詢(PromQL 問 Mimir、LogQL 問 Loki,跟儀表板用的是同一種問法),把結果跟門檻比,連續超標撐過 for 這段時間,才真的觸發。這裡最容易被忽略、卻最關鍵的是 for——它是一條告警的「抗抖動閥」:

告警的狀態機:for 把短暫抖動吸收掉 查詢值 vs 門檻(每個 interval 評估一次) 門檻 短暫尖峰(< for) 持續超標(≥ for) Normal 超門檻 Pending在 for 期間持續觀察 撐過 for Firing 送通知 沒撐過 for → 回 Normal(不 page) for 是抗抖動閥:短暫尖峰在 Pending 就被吸收,只有真正持續的問題才會吵醒你
一條告警規則的一生:Normal → 值超過門檻進 Pending撐過 for 才進 Firing 送通知。for 是最容易被漏掉、卻最救命的一格:一次網路抖動、一次 GC 造成的瞬間尖峰,如果沒撐過 for,就在 Pending 階段被吸收掉、回 Normal,不會 page。少了它,你的告警會因為每個毛刺狂響——而一個會亂叫的告警,很快就會被所有人靜音,等於沒有

有一點值得單獨強調:Grafana 的告警是跨 data source 的——同一套規則引擎,可以拿 PromQL 對指標下門檻、也可以拿 LogQL 對日誌數量下門檻。所以「告警」在這套裡不是某個支柱的附屬功能,而是架在三支柱之上的一層。它跟儀表板共用同一種查詢語言,這代表:你能一眼看懂的儀表板,就能直接長成一條告警——看見與告警,是同一個問句的兩種輸出。

規則與通知解耦:alert 帶 label,notification policy 分流

第二個關鍵設計,是 Grafana 刻意把「什麼壞了」和「通知誰」拆成兩件事。告警規則觸發時,產生的不是一則寫死收件人的訊息,而是一個帶著一組 label 的 alert(severity=criticalteam=payments…)。它要送去哪、吵醒誰,完全由另一個東西——notification policy(一棵 routing tree)——依 label 比對後決定:

規則只管「發生什麼」,策略才管「通知誰」 觸發的 alert 帶著一組 label severity=critical team=payments alertname=5xx高 帶 label 送去 通知策略(routing) 依 label 比對,由上往下 severity=critical ✓ severity=warning default(其它) PagerDuty打電話叫醒值班 Slack #alerts Email(存查) 告警規則不知道也不在乎通知誰 —— 兩層靠 label 解耦,改路由不用動規則
告警規則只負責判斷「發生什麼」並貼上 label;通知策略才負責「通知誰、多急」。這層解耦很值錢:severity=criticalPagerDuty 半夜打電話,warningSlack 白天看,其它進 Email 存查——而這一切都是路由設定,改「誰值班、哪個管道」時,一條告警規則都不用動。策略層還順手做兩件事:grouping(把同批告警併成一則,不然一次當機轟你五十封)和 silence(維護時段先靜音,避免計劃性施工也 page)

好告警的唯一標準:每一則都能「行動」

機制講完,剩下最難、也最重要的一問:什麼該告警? 我的判準只有一條——每一則會 page 你的告警,都必須是「收到就有明確動作」的。從這條會長出兩個具體原則:一是對症狀告警,不對原因告警(alert on symptoms):使用者痛的是「結帳失敗率破 5%」「p99 破 2 秒」,不是「某台 CPU 到 90%」——CPU 高但使用者沒事,你不該被吵醒。二是分級:真的要人半夜起床處理的,才配 page;其餘降級成 Slack、看板。更成熟的做法是接上 SLO 的 error budget,用燒錢速率(burn rate)告警——「照這個速度,budget 幾小時內燒完」——比單一門檻更貼近「使用者到底痛不痛」。這一段的完整戰術,我在 SRE 告警與 on-call那篇講得更細;這裡只留一句心法:告警的品質,不看你設了幾條,看你半夜被吵醒時,有幾則是白吵的。

反思

不能行動的告警,不是告警,是雜訊

我對告警的態度,是被一次慘痛經驗校正的。早期我們的心態是「多設總比漏設好」,於是 CPU、記憶體、磁碟、每個微服務的每個指標,全掛上門檻。結果是一天上百則告警塞爆頻道,大家先是一則則看,接著開始略過,最後整個頻道被 mute——真正該救命的那一則 5xx 暴衝,就淹死在雜訊裡,沒人看到。那次之後我立了一條鐵規:一則告警要能存在,先回答「收到它,我下一步做什麼?」——答不出具體動作的,一律砍掉或降級成看板。 告警不是「把所有異常都吼出來」,是「只在需要人動手時,才動用人的注意力」。人的注意力是整個 on-call 系統裡最貴、最容易耗盡的資源——每多一則沒用的告警,都是在替真正重要的那則挖墳。 我現在評估一套告警是否健康,不看規則數量,看一個數字:每週的告警裡,有多少則事後被判定「其實不用理」——這個比例,就是這套系統正在浪費多少信任。

對症狀告警,把「為什麼」留給那塊玻璃

「對症狀不對原因」這條,想通之後,我發現它剛好把整個 LGTM 系列串了起來。告警負責的是最粗的那一格——「使用者有沒有在痛」,它只要夠準地把人叫醒就好,不需要在告警訊息裡塞滿原因。因為「為什麼痛」那一段,正是後面那塊玻璃、那三支柱要接手的:被 page 醒之後,我打開 Grafana,沿著由粗到細收斂——先看儀表板確認症狀範圍,用 trace 縮到哪個服務哪一段,再鑽進那一小段的 log 看到底是什麼。告警與觀測,是一組漂亮的分工:告警只管「叫不叫人」,診斷交給玻璃。 硬要在告警規則裡塞一堆原因判斷,只會讓它又脆又吵——讓告警保持愚蠢而可靠,把聰明留給事後那塊玻璃。

這篇是整個系列的 payoff:把玻璃接上人

寫到這篇,我才覺得這個系列真正閉環了。從第一篇我就一直說「觀測的終點是行動」,而告警,就是「觀測」與「行動」之間那條實體的線——沒有它,前面六篇蓋起來的一切,都只是等人剛好在看的漂亮儀表板。但我想收一個更進一步的判斷:告警不是設完就結束的東西,它是會演進的。 最好的告警規則,幾乎都不是一開始設計出來的,而是每次事故的 postmortem 長出來的——這次半夜被一個沒用的告警吵醒,下次就把它降級;這次一個真問題沒告警、靠人肉發現,下次就補一條。所以我把「調整告警」列進每份 事後檢討的固定動作:每一次事故,都該讓你的告警比昨天更準一點。 一套觀測系統成不成熟,最終不看它今天多完整,看它有沒有一個「從事故裡持續自我修正」的迴路——能看見,只是起點;能在對的時間叫對的人、做對的事,才是這一整套的終點。