這將是一個系列,講解 夜鶯監控 的設計思考,可以理解為原理+最佳實踐+產品設計時的折中取捨。
整體定位
瞭解一個開源項目,最應該瞭解的就是其定位,或者説它要解決的問題域。
夜鶯的定位就是四個字:告警引擎。夜鶯對接多種數據源(比如 Prometheus、VictoriaMetrics、MySQL、ClickHouse、Postgres、ElasticSearch),根據用户配置的告警規則,判定併產生告警事件,然後對事件做 Pipeline 處理,最終通過各類通知媒介發出告警。
可以對比 Grafana 來理解,Grafana 也是對接多種數據源,不過 Grafana 側重在數據可視化,夜鶯側重在告警。
沒有夜鶯之前,各個數據源的告警是怎麼處理的?
- Prometheus 是直接配置在 prometheus.yml 裏,管理起來稍有不便
- VictoriaMetrics 是使用 vmalert,和 Prometheus 是類似的邏輯
- ElasticSearch 社區裏用的比較多的是 elastalert 開源項目做告警判定
- ClickHouse、MySQL、Postgres 等貌似沒有專門的告警引擎
有了夜鶯之後,就可以在夜鶯裏統一管理告警規則、通知媒介、消息模板、用户聯繫方式等。而且,夜鶯可以對告警事件做 Pipeline 處理,比如:
- Relabel:類似指標的 Relabel,夜鶯可以對告警事件做 Relabel
- Enrichment:事件豐富,比如調用 CMDB 的接口為事件附加更多豐富的上下文信息
- Drop:一些特定的告警事件要丟棄掉
- 等等
夜鶯的核心功能部件
確定了定位之後,如果你是夜鶯的設計者,要如何設計其功能部件呢?
首先,需要一個 webapi。用於和用户、第三方交互,用户需要做一些配置,比如:
- 數據源的配置
- 用户、角色的管理
- 用户聯繫方式管理(比如電話、手機號等,未來在告警觸發時,要打電話發告警短信等)
- 各類規則配置,比如告警規則、屏蔽規則、訂閲規則
- 通知媒介、消息模板的管理
- Pipeline 的管理
- 查看歷史告警事件,做一些統計分析等
其次,需要有一個後台任務執行的邏輯,根據用户配置的告警規則,週期性執行,去查詢數據源,判定數據異常並生成告警事件,最終發送。
- 最簡單的就是一個告警規則一個 goroutine(輕量級線程)後台執行
- 如果執行失敗,通過某些監控指標反應異常,同時打印執行失敗的日誌
- 需要考慮高可用,如果某個實例掛了,其他實例要頂上來
- 需要考慮 sharding,比如有兩個實例,有 1000 條規則,那每個實例要處理 500 條規則,不能重複執行,而且要均勻分配,如果某個實例掛了,剩下的實例要能承接原本宕機的實例負責的那些規則
- 對於某個實例而言,就要知道當前總共有多少實例,哪些實例存活,哪些實例掛了,否則,我不知道誰掛了我就沒法接管。這需要一箇中心狀態存儲,或者引入 Raft 等協議
這個功能部件主要是負責告警,姑且稱之為 alert。所以,夜鶯至少有兩個功能部件:webapi + alert。實際上,夜鶯還有其他功能部件,後文再説。
單進程還是多進程
剛才講,夜鶯至少包含兩個功能部件:webapi + alert。那是做成一個進程?還是做成兩個進程?
如果是公司內部的系統,我更傾向於做成兩個進程,方便維護。但作為一個開源項目,還要考慮普通用户的部署複雜度,則更傾向於做成一個進程。
高可用設計
對於 webapi 功能部件而言,是一個無狀態的組件,接收 api 請求然後對數據庫做 CRUD,所以 webapi 可以水平擴展,部署多個,前面架設負載均衡,就是高可用了。
alert 模塊需要協調分配告警規則,是有狀態的,既然我們不可避免要使用數據庫存儲各類配置信息,那就順便用數據庫存儲 alert 的心跳信息得了,比較簡單。
所以,所有 alert 複用一個 MySQL,週期性心跳,這樣 DB 的心跳錶裏就可以查到所有實例列表,以及最近一次心跳時間,從而得知哪些實例活着哪些已經掛了(長時間沒有心跳就認為掛了)。
這樣的架構極為簡單,每個實例的配置都是相同的,要做高可用就搞多個機器部署多個實例即可。社區用户用起來也簡單。
後記
本文介紹了夜鶯的定位、架構、單進程還是多進程的抉擇、高可用設計,如果你們公司只有一個機房或者有多個機房但是機房之間有很好的網絡專線,那就部署一套夜鶯就可以了,如果有多個機房,但是機房之間的網絡鏈路很差,就需要考慮夜鶯的邊緣機房架構模式,咱們下一節詳細介紹。