基于Alertmanager設計告警降噪系統(tǒng),成本低可落地
一、背景
轉轉基于Prometheus落地了一體化監(jiān)控系統(tǒng),并自研了告警系統(tǒng),但研發(fā)同學每人每天都會接收到很多告警,導致重要的告警被淹沒,部分同學會選擇直接屏蔽掉所有告警,進一步加重問題。告警過多等同于沒有告警。
另外,多個告警之間通常具有一定的關聯(lián)性,如:SQL執(zhí)行錯誤告警導致異常日志過多告警。而面對雜亂無章的告警,很難快速分析出告警的根本原因。
告警降噪治理十分重要,在此背景下,我們基于Alertmanager擴展研發(fā)了轉轉告警中心。
二、規(guī)范與SDK
2.1 發(fā)送告警
Alertmanager提供了告警發(fā)送的OpenAPI,其中,告警的labels用于識別同一條告警并對告警去重、降噪,相同labels的告警的annotations會被覆蓋。startsAt與endsAt分別為告警發(fā)生時間與結束時間。
一條告警從提交到發(fā)送再到接收人的流程大致如下圖所示,其中,Alertmanager需要集群部署來保證高可用性,需要注意的是,發(fā)送告警時不能對集群做負載均衡,必須要對集群內所有的Alertmanager發(fā)送告警才能保證高可用性。
2.2 常用標簽
Alertmanager為基于標簽的告警降噪,需提前規(guī)范告警常見標簽。
- ENV:環(huán)境,如:線上環(huán)境、測試環(huán)境
- APP:服務名
- SOURCE:告警來源,如:日志告警、JVM告警
- NAME:告警名稱
- LEVEL:告警等級,如:P0告警、P5告警
- INSTANCE:告警實例IP
- RECEIVER_TYPE:告警接受者類型
- RECEIVER:告警接受者,與RECEIVER_TYPE配合使用,如RECEIVER_TYPE=郵件,RECEIVER即為郵箱地址。
Alertmanager標簽名的正則規(guī)則為??[a-zA-Z_][a-zA-Z0-9_]*?
?,在真正發(fā)送通知時,最好將標簽名做一次中文映射轉換。
2.3 SDK
我們針對Alertmanager開發(fā)了發(fā)送告警的SDK,如下所示,發(fā)送告警非常簡單,SDK默認會為每條告警自動增加服務名、環(huán)境、IP、告警等級,并按照接收方拆開為多條告警發(fā)送。每一項內容都是標簽,其中value較為特殊,放在了annotations內,其他均放在了labels內用于唯一識別一條告警。
三、告警降噪
3.1 分組去重
分組機制可以將多條告警信息合并成一個通知。例如,當集群中有數百個正在運行的服務實例,假如此時發(fā)生了網絡故障,結果就會有數百個告警被發(fā)送到Alertmanager。
而作為用戶,可能只希望能夠在一個通知中就能查看哪些服務實例受到影響。這時可以按照服務所在集群或者告警名稱對告警進行分組,將這些告警聚合在一起成為一個通知。
Alertmanager可以將收到的告警按照特定的標簽分組、去重,并基于以下參數決定何時發(fā)送組內的告警通知,Alertmanager的每一次通知都會包含當前組內的所有告警。
- 初始等待時間(group_wait):一組告警第一次發(fā)送之前等待的時間,用于等待同一組的更多告警合并發(fā)送。
- 變化等待時間(group_interval):一組已發(fā)送初始通知的告警在接收到新告警或有告警恢復后,再次發(fā)送通知前等待的時間。
- 重復等待時間(repeat_interval):一組已發(fā)送初始通知的告警,組內告警均沒有恢復且沒有新增告警,再次發(fā)送通知前等待的時間。
下面以一張圖,來展示從告警產生到合并到某個集合中,到發(fā)送通知的整個過程。三角形和圓形表示不斷產生的告警,矩形代表實際的通知時間以及告警內容。
3.2 恢復通知
Alertmanager自帶恢復通知,默認5m沒有收到告警后,告警將被認為恢復,然后會等待group_interval后通知給用戶。發(fā)送告警時也可以指定告警恢復時間,如下所示:
需要注意的是,endTime如果小于當前時間,會認為告警在發(fā)出時就已經恢復,這條告警不會通知。
3.3 告警分級
我們將告警分為P0~P5六個等級,告警等級默認取決于服務重要性,轉轉服務按照重要性分了A、B、C、D、E五個等級,服務重要性與告警等級的對應關系:A → P1,B → P2,C → P3,D → P4,E → P5。發(fā)送告警時也可以指定告警等級,如下:
告警分級的目的是盡量讓高等級的告警及時發(fā)出,低等級的告警減少用戶打擾次數。不同等級告警的分組、去重時間均不相同。
如:P4/P5的告警初始時會等待3m收集告警,并將當前告警接收者的所有告警匯總到一條通知內;
P0的告警只會等待15s收集告警,并按照告警接收者、環(huán)境、服務名、告警來源、告警名稱為維度拆分成多個通知。
告警等級 | 分組標簽 | group_wait | group_interval | repeat_interval |
P0 | 告警接收者、環(huán)境、服務名、告警來源、告警名稱 | 15s | 1m | 30m |
P1 | 告警接收者、環(huán)境、服務名、告警來源 | 30s | 5m | 1h |
P2 | 告警接收者、環(huán)境、服務名 | 1m | 5m | 1h |
P3 | 告警接收者、環(huán)境 | 2m | 10m | 2h |
P4/P5 | 告警接收者 | 3m | 10m | 4h |
3.4 通知合并
統(tǒng)一使用Alertmanager webhook通知,一次通知內容會包含分組內的多個報警,我們會按照告警相似度對告警做合并,如下為6條報警合并成一條通知,其中,告警值與服務實例一一對應。
定義相似度:對于多個報警的labels,只有一個label value不一樣,剩余的label key與label value均相同,則認為相似并合并;一次Alertmanager webhook通知可按照相似度拆分成多種告警,不同的告警提取公共標簽,最終推送到一條通知內。
如下,為4條告警合并到一條通知,可清晰的看到兩臺機器的異常日志報警的原因是由于Druid執(zhí)行SQL錯誤導致。
3.5 告警抑制
抑制是指當某一告警發(fā)出后,可以停止重復發(fā)送由此告警引發(fā)的其它告警的機制。
當同一個服務、環(huán)境、告警來源、IP、接受者、告警名稱,同時出現多個等級的告警時,高等級的告警會抑制低等級告警的通知。
如:告警名稱為FGC次數,P1告警閾值為20次,P2告警為10次,當某個實例的FGC次數達到20次以上時,只會發(fā)送P1告警,不會發(fā)送P2告警。
四、多通知機制
支持企業(yè)微信、企業(yè)微信群、短信、郵件、電話、WebHook,可在一個告警內同時指定多種接收方式,我們會自動按照接收人拆分成多條告警。
- 企業(yè)微信、企業(yè)微信群、郵件、WebHook:最詳細,發(fā)送告警與恢復通知。
- 短信:相對以上,只是不會發(fā)送恢復通知。
- 電話:不會發(fā)送恢復通知,并且只會播報報警標題與告警服務名。
五、未恢復告警
為了防止告警過多時淹沒了重要告警,在每條告警的最后,都提供了一個未恢復告警鏈接,用于實時查詢當前未恢復的告警。
未恢復告警擁有三種狀態(tài):活躍、靜默、抑制。其中,活躍狀態(tài)可以設置靜默,靜默狀態(tài)可以查看被誰靜默。
六、靜默告警
基于Alertmanager OpenAPI,支持基于標簽的靜默告警,每條告警通知內都提供了一個鏈接用于快速靜默,也可以在未恢復告警內靜默告警。
點擊新增靜默后,會自動補充靜默匹配的標簽項,也可以增減標簽項,如:去掉INSTANCE標簽維度以便匹配所有的機器,修改_RECEIVER為其他人等。需要注意的是,添加靜默時RECEIVER必須要指定。
添加完成后,會自動跳轉到靜默列表,并展示剛剛添加的靜默項。
在靜默列表內可查詢所有的活躍、過期的靜默項,可編輯、刪除、查看影響的告警。
查看受影響的告警為實時查詢,如果當前靜默沒有匹配到任何告警,查詢結果會為空。
七、告警歷史
告警通知給用戶后,我們會保留三個月的歷史告警記錄列表。
八、總結
Alertmanager提供了告警降噪的策略,我們在Alertmanager的基礎上制定了標簽規(guī)范、告警分級降噪、分級抑制、告警合并,并基于Alertmanager OpenAPI擴展了未恢復告警、靜默告警、告警歷史。Alertmanager雖然不是告警降噪的銀彈,但也可以解決大部分問題,如果你也面臨著告警轟炸的問題,可以嘗試一下。
關于作者
苑沖,轉轉架構部存儲服務負責人,主要負責MQ、監(jiān)控系統(tǒng)、Redis、KV存儲等。愛學習,喜歡以辯證思維與變化思維思考。