為了提升promthues的服務可用性,通常使用者會部署兩個或者兩個以上的promthus server,它們具有完全相同的配置包括job配置,以及告警配置等。當某一個prometheus server發生故障後可以確定promthues持續可用。
同時基于alertmanager的告警分組機制即使不同的prometheus sever分别發送相同的告警給alertmanager,alertmanager也可以自動将這些告警合并為一個通知向receiver發送。
但不幸的是,雖然alertmanager能夠同時處理多個相同的prometheus server所産生的告警。但是由于單個alertmanager的存在,目前的部署結構存在明顯的單點故障風險,當alertmanager單點失效後,告警的後續所有業務全部失效。
如下所示,最直接的方式,就是嘗試部署多套alertmanager。但是由于alertmanager之間不存在并不了解彼此的存在,是以則會出現告警通知被不同的alertmanager重複發送多次的問題。
為了解決這一問題,如下所示。alertmanager引入了gossip機制。gossip機制為多個alertmanager之間提供了資訊傳遞的機制。確定及時在多個alertmanager分别接收到相同告警資訊的情況下,也隻有一個告警通知被發送給receiver。
gossip協定
gossip是分布式系統中被廣泛使用的協定,用于實作分布式節點之間的資訊交換和狀态同步。gossip協定同步狀态類似于流言或者病毒的傳播,如下所示:
一般來說gossip有兩種實作方式分别為push-based和pull-based。在push-based當叢集中某一節點a完成一個工作後,随機的從其它節點b并向其發送相應的消息,節點b接收到消息後在重複完成相同的工作,直到傳播到叢集中的所有節點。而pull-based的實作中節點a會随機的向節點b發起詢問是否有新的狀态需要同步,如果有則傳回。
在簡單了解了gossip協定之後,我們來看alertmanager是如何基于gossip協定實作叢集高可用的。如下所示,當alertmanager接收到來自prometheus的告警消息後,會按照以下流程對告警進行處理:
1.在第一個階段silence中,alertmanager會判斷目前通知是否比對到任何的靜默規則,如果沒有則進入下一個階段,否則則中斷流水線不發送通知。
2.在第二個階段wait中,alertmanager會根據目前alertmanager在叢集中所在的順序(index)等待index * 5s的時間。
3.目前alertmanager等待階段結束後,dedup階段則會判斷目前alertmanager資料庫中該通知是否已經發送,如果已經發送則中斷流水線,不發送告警,否則則進入下一階段send對外發送告警通知。
4.告警發送完成後該alertmanager進入最後一個階段gossip,gossip會通知其他alertmanager執行個體目前告警已經發送。其他執行個體接收到gossip消息後,則會在自己的資料庫中儲存該通知已發送的記錄。
是以如下所示,gossip機制的關鍵在于兩點:
silence設定同步:alertmanager啟動階段基于pull-based從叢集其它節點同步silence狀态,當有新的silence産生時使用push-based方式在叢集中傳播gossip資訊。
通知發送狀态同步:告警通知發送完成後,基于push-based同步告警發送狀态。wait階段可以確定叢集狀态一緻。
alertmanager基于gossip實作的叢集機制雖然不能保證所有執行個體上的資料時刻保持一緻,但是實作了cap理論中的ap系統,即可用性和分區容錯性。同時對于prometheus server而言保持了配置了簡單性,promthues server之間不需要任何的狀态同步。
搭建本地叢集環境
為了能夠讓alertmanager節點之間進行通訊,需要在alertmanager啟動時設定相應的參數。其中主要的參數包括:
—cluster.listen-address string: 目前執行個體叢集服務監聽位址
—cluster.peer value: 初始化時關聯的其它執行個體的叢集服務位址
例如:
定義alertmanager執行個體a1,其中alertmanager的服務運作在9093端口,叢集服務位址運作在8001端口。
定義alertmanager執行個體a2,其中主服務運作在9094端口,叢集服務運作在8002端口。為了将a1,a2組成叢集。 a2啟動時需要定義—cluster.peer參數并且指向a1執行個體的叢集服務位址:8001。
為了能夠在本地模拟叢集環境,這裡使用了一個輕量級的多線程管理工具goreman。使用以下指令可以在本地安裝goreman指令行工具。
建立alertmanager配置檔案/etc/prometheus/alertmanager-ha.yml, 為了驗證alertmanager的叢集行為,這裡在本地啟動一個webhook服務用于列印alertmanager發送的告警通知資訊。
本地webhook服務可以直接從github擷取。
示例結構如下所示:
建立alertmanager.procfile檔案,并且定義了三個alertmanager節點(a1,a2,a3)以及用于接收告警通知的webhook服務:
在procfile檔案所在目錄,執行goreman start指令,啟動所有程序:
啟動完成後通路任意alertmanager節點http://localhost:9093/#/status,可以檢視目前alertmanager叢集的狀态。
當叢集中的alertmanager節點不在一台主機時,通常需要使用—cluster.advertise-address參數指定目前節點所在網絡位址。
注意:由于goreman不保證程序之間的啟動順序,如果叢集狀态未達到預期,可以使用goreman -f alertmanager.procfile run restart a2重新開機a2,a3服務。
當alertmanager叢集啟動完成後,可以使用send-alerts.sh腳本對叢集進行簡單測試,這裡利用curl分别向3個alertmanager執行個體發送告警資訊。
運作send-alerts.sh後,檢視alertmanager日志,可以看到以下輸出,3個alertmanager執行個體分别接收到模拟的告警資訊:
檢視webhook日志隻接收到一個告警通知:
由于gossip機制的實作,在promthues和alertmanager執行個體之間不要使用任何的負載均衡,需要確定promthues将告警發送到所有的alertmanager執行個體中:
建立promthues叢集配置檔案/etc/prometheus/prometheus-ha.yml,完整内容如下:
同時定義告警規則檔案/etc/prometheus/rules/hoststats-alert.rules,如下所示:
本示例部署結構如下所示:
建立prometheus.procfile檔案,建立兩個promthues節點,分别監聽9090和9091端口:
使用goreman啟動多節點promthues:
promthues啟動完成後,手動拉高系統cpu使用率:
注意,對于多核主機,如果cpu達不到預期,運作多個指令。
當cpu使用率達到告警規則觸發條件,兩個prometheus執行個體告警分别被觸發。檢視alertmanager輸出日志:
3個alertmanager執行個體分别接收到來自不同prometheus執行個體的告警資訊。而webhook服務隻接收到來自alertmanager叢集的一條告警通知: