1. 程式人生 > 其它 >【轉】Alertmanager高可用

【轉】Alertmanager高可用

轉, 原文:https://yunlzheng.gitbook.io/prometheus-book/part-ii-prometheus-jin-jie/readmd/alertmanager-high-availability

---------------------------

在上一小節中我們主要討論了Prometheus Server自身的高可用問題。而接下來,重點將放在告警處理也就是Alertmanager部分。如下所示。

Alertmanager成為單點

為了提升Promthues的服務可用性,通常使用者會部署兩個或者兩個以上的Promthus Server,它們具有完全相同的配置包括Job配置,以及告警配置等。當某一個Prometheus Server發生故障後可以確保Promthues持續可用。

同時基於Alertmanager的告警分組機制即使不同的Prometheus Sever分別傳送相同的告警給Alertmanager,Alertmanager也可以自動將這些告警合併為一個通知向receiver傳送。

Alertmanager特性

但不幸的是,雖然Alertmanager能夠同時處理多個相同的Prometheus Server所產生的告警。但是由於單個Alertmanager的存在,當前的部署結構存在明顯的單點故障風險,當Alertmanager單點失效後,告警的後續所有業務全部失效。

如下所示,最直接的方式,就是嘗試部署多套Alertmanager。但是由於Alertmanager之間不存在並不瞭解彼此的存在,因此則會出現告警通知被不同的Alertmanager重複傳送多次的問題。

為了解決這一問題,如下所示。Alertmanager引入了Gossip機制。Gossip機制為多個Alertmanager之間提供了資訊傳遞的機制。確保及時在多個Alertmanager分別接收到相同告警資訊的情況下,也只有一個告警通知被髮送給Receiver。

Alertmanager Gossip Gossip協議

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機制的關鍵在於兩點:

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 --web.listen-address=":9093" --cluster.listen-address="127.0.0.1:8001" --config.file=/etc/prometheus/alertmanager.yml --storage.path=/data/alertmanager/

定義Alertmanager例項a2,其中主服務執行在9094埠,叢集服務執行在8002埠。為了將a1,a2組成叢集。 a2啟動時需要定義--cluster.peer引數並且指向a1例項的叢集服務地址:8001。

alertmanager --web.listen-address=":9094" --cluster.listen-address="127.0.0.1:8002" --cluster.peer=127.0.0.1:8001 --config.file=/etc/prometheus/alertmanager.yml --storage.path=/data/alertmanager2/

為了能夠在本地模擬叢集環境,這裡使用了一個輕量級的多執行緒管理工具goreman。使用以下命令可以在本地安裝goreman命令列工具。

go get github.com/mattn/goreman 建立Alertmanager叢集

建立Alertmanager配置檔案/etc/prometheus/alertmanager-ha.yml, 為了驗證Alertmanager的叢集行為,這裡在本地啟動一個webhook服務用於列印Alertmanager傳送的告警通知資訊。

route: receiver: 'default-receiver' receivers: - name: default-receiver webhook_configs: - url: 'http://127.0.0.1:5001/'

本地webhook服務可以直接從Github獲取。

# 獲取alertmanager提供的webhook示例,如果該目錄下定義了main函式,go get會自動將其編譯成可執行檔案 go get github.com/prometheus/alertmanager/examples/webhook # 設定環境變數指向GOPATH的bin目錄 export PATH=$GOPATH/bin:$PATH # 啟動服務 webhook

示例結構如下所示:

Alertmanager HA部署結構

建立alertmanager.procfile檔案,並且定義了三個Alertmanager節點(a1,a2,a3)以及用於接收告警通知的webhook服務:

a1: alertmanager --web.listen-address=":9093" --cluster.listen-address="127.0.0.1:8001" --config.file=/etc/prometheus/alertmanager-ha.yml --storage.path=/data/alertmanager/ --log.level=debug a2: alertmanager --web.listen-address=":9094" --cluster.listen-address="127.0.0.1:8002" --cluster.peer=127.0.0.1:8001 --config.file=/etc/prometheus/alertmanager-ha.yml --storage.path=/data/alertmanager2/ --log.level=debug a3: alertmanager --web.listen-address=":9095" --cluster.listen-address="127.0.0.1:8003" --cluster.peer=127.0.0.1:8001 --config.file=/etc/prometheus/alertmanager-ha.yml --storage.path=/data/alertmanager2/ --log.level=debug webhook: webhook

在Procfile檔案所在目錄,執行goreman start命令,啟動所有程序:

$ goreman -f alertmanager.procfile start 10:27:57 a1 | level=debug ts=2018-03-12T02:27:57.399166371Z caller=cluster.go:125 component=cluster msg="joined cluster" peers=0 10:27:57 a3 | level=info ts=2018-03-12T02:27:57.40004678Z caller=main.go:346 msg=Listening address=:9095 10:27:57 a1 | level=info ts=2018-03-12T02:27:57.400212246Z caller=main.go:271 msg="Loading configuration file" file=/etc/prometheus/alertmanager.yml 10:27:57 a1 | level=info ts=2018-03-12T02:27:57.405638714Z caller=main.go:346 msg=Listening address=:9093

啟動完成後訪問任意Alertmanager節點http://localhost:9093/#/status,可以檢視當前Alertmanager叢集的狀態。

Alertmanager叢集狀態

當叢集中的Alertmanager節點不在一臺主機時,通常需要使用--cluster.advertise-address引數指定當前節點所在網路地址。

注意:由於goreman不保證程序之間的啟動順序,如果叢集狀態未達到預期,可以使用goreman -f alertmanager.procfile run restart a2重啟a2,a3服務。

當Alertmanager叢集啟動完成後,可以使用send-alerts.sh指令碼對叢集進行簡單測試,這裡利用curl分別向3個Alertmanager例項傳送告警資訊。

alerts1='[ { "labels": { "alertname": "DiskRunningFull", "dev": "sda1", "instance": "example1" }, "annotations": { "info": "The disk sda1 is running full", "summary": "please check the instance example1" } }, { "labels": { "alertname": "DiskRunningFull", "dev": "sdb2", "instance": "example2" }, "annotations": { "info": "The disk sdb2 is running full", "summary": "please check the instance example2" } }, { "labels": { "alertname": "DiskRunningFull", "dev": "sda1", "instance": "example3", "severity": "critical" } }, { "labels": { "alertname": "DiskRunningFull", "dev": "sda1", "instance": "example3", "severity": "warning" } } ]' curl -XPOST -d"$alerts1" http://localhost:9093/api/v1/alerts curl -XPOST -d"$alerts1" http://localhost:9094/api/v1/alerts curl -XPOST -d"$alerts1" http://localhost:9095/api/v1/alerts

執行send-alerts.sh後,檢視alertmanager日誌,可以看到以下輸出,3個Alertmanager例項分別接收到模擬的告警資訊:

10:43:36 a1 | level=debug ts=2018-03-12T02:43:36.853370185Z caller=dispatch.go:188 component=dispatcher msg="Received alert" alert=DiskRunningFull[6543bc1][active] 10:43:36 a2 | level=debug ts=2018-03-12T02:43:36.871180749Z caller=dispatch.go:188 component=dispatcher msg="Received alert" alert=DiskRunningFull[8320f0a][active] 10:43:36 a3 | level=debug ts=2018-03-12T02:43:36.894923811Z caller=dispatch.go:188 component=dispatcher msg="Received alert" alert=DiskRunningFull[8320f0a][active]

檢視webhook日誌只接收到一個告警通知:

10:44:06 webhook | 2018/03/12 10:44:06 { 10:44:06 webhook | > "receiver": "default-receiver", 10:44:06 webhook | > "status": "firing", 10:44:06 webhook | > "alerts": [ 10:44:06 webhook | > { 10:44:06 webhook | > "status": "firing", 10:44:06 webhook | > "labels": { 10:44:06 webhook | > "alertname": "DiskRunningFull", 多例項Prometheus與Alertmanager叢集

由於Gossip機制的實現,在Promthues和Alertmanager例項之間不要使用任何的負載均衡,需要確保Promthues將告警傳送到所有的Alertmanager例項中:

alerting: alertmanagers: - static_configs: - targets: - 127.0.0.1:9093 - 127.0.0.1:9094 - 127.0.0.1:9095

建立Promthues叢集配置檔案/etc/prometheus/prometheus-ha.yml,完整內容如下:

global: scrape_interval: 15s scrape_timeout: 10s evaluation_interval: 15s rule_files: - /etc/prometheus/rules/*.rules alerting: alertmanagers: - static_configs: - targets: - 127.0.0.1:9093 - 127.0.0.1:9094 - 127.0.0.1:9095 scrape_configs: - job_name: prometheus static_configs: - targets: - localhost:9090 - job_name: 'node' static_configs: - targets: ['localhost:9100']

同時定義告警規則檔案/etc/prometheus/rules/hoststats-alert.rules,如下所示:

groups: - name: hostStatsAlert rules: - alert: hostCpuUsageAlert expr: sum(avg without (cpu)(irate(node_cpu{mode!='idle'}[5m]))) by (instance) * 100 > 50 for: 1m labels: severity: page annotations: summary: "Instance {{ $labels.instance }} CPU usgae high" description: "{{ $labels.instance }} CPU usage above 50% (current value: {{ $value }})" - alert: hostMemUsageAlert expr: (node_memory_MemTotal - node_memory_MemAvailable)/node_memory_MemTotal * 100 > 85 for: 1m labels: severity: page annotations: summary: "Instance {{ $labels.instance }} MEM usgae high" description: "{{ $labels.instance }} MEM usage above 85% (current value: {{ $value }})"

本示例部署結構如下所示:

Promthues與Alertmanager HA部署結構

建立prometheus.procfile檔案,建立兩個Promthues節點,分別監聽9090和9091埠:

p1: prometheus --config.file=/etc/prometheus/prometheus-ha.yml --storage.tsdb.path=/data/prometheus/ --web.listen-address="127.0.0.1:9090" p2: prometheus --config.file=/etc/prometheus/prometheus-ha.yml --storage.tsdb.path=/data/prometheus2/ --web.listen-address="127.0.0.1:9091" node_exporter: node_exporter -web.listen-address="0.0.0.0:9100"

使用goreman啟動多節點Promthues:

goreman -f prometheus.procfile -p 8556 start

Promthues啟動完成後,手動拉高系統CPU使用率:

cat /dev/zero>/dev/null

注意,對於多核主機,如果CPU達不到預期,執行多個命令。

當CPU利用率達到告警規則觸發條件,兩個Prometheus例項告警分別被觸發。檢視Alertmanager輸出日誌:

11:14:41 a3 | level=debug ts=2018-03-12T03:14:41.945493505Z caller=dispatch.go:188 component=dispatcher msg="Received alert" alert=hostCpuUsageAlert[7d698ac][active] 11:14:41 a1 | level=debug ts=2018-03-12T03:14:41.945534548Z caller=dispatch.go:188 component=dispatcher msg="Received alert" alert=hostCpuUsageAlert[7d698ac][active] 11:14:41 a2 | level=debug ts=2018-03-12T03:14:41.945687812Z caller=dispatch.go:188 component=dispatcher msg="Received alert" alert=hostCpuUsageAlert[7d698ac][active]

3個Alertmanager例項分別接收到來自不同Prometheus例項的告警資訊。而Webhook服務只接收到來自Alertmanager叢集的一條告警通知:

11:15:11 webhook | 2018/03/12 11:15:11 { 11:15:11 webhook | > "receiver": "default-receiver", 11:15:11 webhook | > "status": "firing", 11:15:11 webhook | > "alerts": [ 11:15:11 webhook | > { 11:15:11 webhook | > "status": "firing", 11:15:11 webhook | > "labels": { 11:15:11 webhook | > "alertname": "hostCpuUsageAlert", Previous Prometheus高可用 Next 小結 Last updated3 years ago