天天看點

Prometheus實戰-從0建構高可用監控平台(四)

作者:小毛驢的爛筆頭

當今的網際網路應用系統越來越複雜,其中涉及的元件和服務越來越多,需要進行高效、可靠的監控,以保證系統的穩定性和性能。Prometheus是一款功能強大的開源監控系統,可以實時監控多個次元的名額資料,并支援強大的查詢語言和告警機制,是目前廣泛使用的雲原生應用監控系統之一。

本文檔合集《Prometheus實戰:從0建構高可用監控平台》将從零開始,手把手教您如何建構一套高可用的Prometheus監控平台,涵蓋了以下内容:

1. Prometheus叢集搭建:實作高可用和可擴充的監控系統

2. 動态監控名額:自動發現和注冊要監控的目标

3. 告警機制配置:靈活配置告警規則、分組、過濾、抑制,實時通知異常情況

4. Grafana可視化展示:直覺了解系統運作狀态和趨勢

本文檔合集的目标讀者是具有一定Linux系統和網絡知識的系統管理者和DevOps工程師。通過本文檔合集的學習,您将掌握Prometheus的核心概念和實踐技巧,能夠快速搭建一套高效、可靠的監控平台,幫助您更好地管理和維護複雜的網際網路應用系統。

本文以下内容是基于 Alertmanager 靈活配置告警規則、分組、過濾、抑制。

Alertmanager

Alertmanager 是 Prometheus 生态系統中的一個元件,用于處理告警資訊。Alertmanager 的主要作業包括以下幾個方面:

  1. 1. 接收告警資訊:Alertmanager 從 Prometheus 或其他資料源接收告警資訊,并對其進行處理。
  2. 2. 分組和去重:Alertmanager 可以根據标簽對告警資訊進行分組,并去除重複的告警資訊。
  3. 3. 通知:Alertmanager 可以通過電子郵件、釘釘、飛書、Webhook 等方式發送告警通知。
  4. 4. 告警靜默:Alertmanager 允許使用者對某些告警規則進行靜默處理,以避免過多的告警資訊幹擾使用者。

Alertmanager 是 Prometheus 監控系統中非常重要的一個元件。如果保證它的高可用有以下兩種方式:

1 多執行個體部署

可以将多個 Alertmanager 執行個體部署在不同的節點上,并使用負載均衡器(例如 Nginx、HAProxy 等)将請求分發到這些執行個體上。多執行個體部署可以提高 Alertmanager 的可用性,當某個 Alertmanager 執行個體故障時,請求可以自動轉發到其他正常工作的執行個體。

2 原生 HA 方案

從 Alertmanager v0.16.0 版本開始,Alertmanager 提供了一種原生的高可用方案,即使用 Raft 算法進行狀态同步和故障轉移。在原生 HA 方案中,多個 Alertmanager 執行個體會形成一個 Raft 叢集,其中一個執行個體會被選舉為 leader,負責處理請求和寫入狀态。其他執行個體則作為 follower,從 leader 同步狀态,并在 leader 故障時自動切換為新的 leader。

安裝之前的規劃,我們這裡使用多執行個體部署的方式完全都能夠滿足我們的需求。

部署Alertmanager 服務

node2 和 node3 部署Alertmanager 服務 操作一樣,配置檔案也一樣。

cd /usr/local/src/
https://github.com/prometheus/alertmanager/releases/download/v0.24.0/alertmanager-0.24.0.linux-amd64.tar.gz

tar xf alertmanager-0.24.0.linux-amd64.tar.gz  -C /usr/local/
ln -sv /usr/local/alertmanager-0.24.0.linux-amd64 /usr/local/alertmanager
chown -R prometheus. /usr/local/alertmanager-0.24.0.linux-amd64 

mkdir /data/alertmanager
chown -R prometheus. /data/alertmanager

cat > /etc/systemd/system/alertmanager.service <<EOF
[Unit]
Description=alertmanager
After=network.target
[Service]
Type=simple
User=prometheus
ExecStart=/usr/local/alertmanager/alertmanager --storage.path=/data/alertmanager/data --config.file /usr/local/alertmanager/alertmanager.yml
Restart=on-failure
LimitNOFILE=655350
LimitNPROC=655350
LimitCORE=infinity
[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl start alertmanager
systemctl enable alertmanager           
生産在用的配置檔案
[root@Q-gz-common-prod-thanos-002 alertmanager]# cat alertmanager.yml | grep  -v "^#"
route:
  #group_by: ['instance']
  group_by: ['alertname', 'severity']
  group_wait: 10s
  group_interval: 3m
  # 重新發送相同告警的間隔。比如我主機當機了,一直沒處理,那麼就一直有告警,發完第一次後以後每次都要等repeat_interval時間才會發送第二次。
  repeat_interval: 5m
  # 比如一個分組同時有A、B兩個告警,A先到達進去group_wait裡面等着,在group_wait期間,B也進來了,兩個合并成一組,并發送一個告警消息出去;發完後A、B的問題還未解決,還持續觸發告警,然後分組内又來了個新告警C,這就觸發了group_interval,由于同組的狀态發生了變化,A、B、C會在group_interval内被快速推送告警,不會等到group_interval後再發;如果發完後,A、B、C三者都持續無變化,那麼就會在repeat_interval周期性發送告警資訊。
  receiver: 'web.hook.prometheusalert'
  routes:
  - receiver: txsms
    continue: true
    group_wait: 30s
    matchers:
    - severity="critical"
  #- receiver: flashcat 
  #  continue: true
  #  group_wait: 30s
  #  matchers:
  #  - severity="error"
  # 配置其他級别的告警通知
  - receiver: web.hook.prometheusalert
    continue: true
    group_wait: 10s
    matchers:
    - severity=~".*"

receivers:
  - name: 'web.hook.prometheusalert'
    webhook_configs:
    - url: 'http://10.2.0.27:18080/prometheusalert?type=fs&tpl=prometheus-fs&fsurl=https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxx'

  - name: 'txsms'
    webhook_configs:
    - url: 'http://10.2.0.27:18080/prometheusalert?type=txdx&tpl=prometheus-dx&phone=1xxxx1,1xxxx2'
      send_resolved: true

  - name: 'flashcat'
    webhook_configs:
    - url: 'https://api.flashcat.cloud/event/push/alert/prometheus?integration_key=11111'
      send_resolved: true

inhibit_rules:
  - source_match:
      severity: 'critical'
    target_match:
      severity: 'error|warning|info|notice'
    equal: ['instance', 'alertname']
  - source_match:
      severity: 'error'
    target_match:
      severity: 'warning|info|notice'
    equal: ['instance', 'alertname']
  - source_match:
      severity: 'warning'
    target_match:
      severity: 'info|notice'
    equal: ['instance', 'alertname']           

下面要基于這個配置說明幾個場景

告警級别規劃

緻命  critical
    嚴重  error
    警告  warning
    提醒  notice
    通知  info           

Alertmanager 主備模式配置

按照之前的規劃, 使用keepalived+haproxy的方式,實作Alertmanager 主備模式,在發生故障的時候進去主備切換。

frontend alertmanager-in
    bind     *:19093
    maxconn  20000
    default_backend alertmanager-out

backend alertmanager-out
    server alertmanager-1    10.2.0.10:9093    maxconn 20480  weight 10  check inter 10s  rise 1 fall 2
    server alertmanager-2    10.2.0.41:9093    maxconn 20480  weight 10  check inter 10s  rise 1 fall 2 backup           

配置告警靜默規則

inhibit_rules 配置段用于配置告警靜默規則,是 Alertmanager 中非常重要的一部分。通過合理配置 inhibit_rules 規則,可以避免向使用者發送過多的告警資訊,提高告警處理的效率。

上面定義了三個 inhibit_rules 規則,每個規則包含 source_match、target_match 和 equal 三個字段:

第一個規則:當源告警的 severity 為 'critical' 時,目标告警的 severity 為 'error|warning|info|notice',且 instance 和 alertname 相同。這個規則的作用是将嚴重級别為 'critical' 的告警靜默處理,避免向使用者發送過多的告警資訊。

第二個規則:當源告警的 severity 為 'error' 時,目标告警的 severity 為 'warning|info|notice',且 instance 和 alertname 相同。這個規則的作用是将錯誤級别為 'error' 的告警靜默處理,避免向使用者發送過多的告警資訊。

第三個規則:當源告警的 severity 為 'warning' 時,目标告警的 severity 為 'info|notice',且 instance 和 alertname 相同。這個規則的作用是将警告級别為 'warning' 的告警靜默處理,避免向使用者發送過多的告警資訊。

基于标簽的告警路由配置

路由配置是 Alertmanager 中非常重要的一部分,它定義了告警的路由規則,用于将告警發送到不同的接收者。通過合理配置路由規則,可以将不同級别、不同類型的告警發送到不同的接收者,實作更加靈活、高效的告警處理。

上面的配置定義了兩個路由規則:

第一個路由規則将 severity 為 'critical' 的告警發送到接收者 'txsms'。其中 continue: true 表示如果告警被路由到這個接收者後,Alertmanager 會繼續嘗試将告警路由到其他接收者。group_wait: 30s 表示如果在 30 秒内有相同的告警被觸發,則會将這些告警分組,一起發送到接收者。

第二個路由規則将所有級别的告警都發送到預設接收者 'web.hook.prometheusalert'。其中 severity=~".*" 表示比對所有 severity 級别的告警。group_wait: 10s 表示将 10 秒内相同的告警分組發送到接收者。注意,這個路由規則的 continue: true 表示即使告警已經被路由到其他接收者,也會嘗試再次發送到預設接收者。

基于業務需求,可以添加更多的通知管道和基于不同的級别的告警選擇。這裡我使用了兩個進階通知管道,短信和飛書。

周期建立告警抑制

在 Alertmanager 中,可以使用 inhibit_rules 選項來建立周期性告警抑制規則。下面是一個示例配置,該配置可以在每個小時的 0 分和 30 分時,對同一個 alertname 和 job 的告警進行周期性抑制,抑制時間為 5 分鐘。該配置還包括了一個預設的抑制規則,對于任何兩個相同的告警,間隔小于 1 分鐘的将被抑制,以避免瞬間重複觸發告警。

inhibit_rules:
  # 預設的抑制規則,對于任何兩個相同的告警,間隔小于 1 分鐘的将被抑制
  - source_match:
      severity: 'critical'
    target_match:
      severity: 'warning|info'
    equal: ['alertname', 'job']
    # 抑制時間為 1 分鐘
    duration: 1m
  # 周期性抑制規則,對于同一個 alertname 和 job 的告警,在每個小時的 0 分和 30 分時,間隔小于 5 分鐘的将被抑制
  - source_match:
      severity: 'critical'
    target_match:
      severity: 'warning|info'
    equal: ['alertname', 'job']
    # 在每個小時的 0 分和 30 分觸發抑制
    periods:
      - start: 0m
        end: 5m
      - start: 30m
        end: 35m           

在上面的配置中,inhibit_rules 選項包含了兩個告警抑制規則。第一個規則是預設的抑制規則,它使用 duration 屬性指定抑制時間為 1 分鐘。第二個規則是周期性抑制規則,它使用 periods 屬性指定在每個小時的 0 分和 30 分時觸發抑制,抑制時間為 5 分鐘。

在實際業務中我們可能需要基于标簽選建立抑制,而不是每次都去修改配置檔案。基于這個需要有兩個方式實作。

使用amtool
# cat amtool_mysql_silence_every_day.sh 
#!/bin/bash

# 擷取明天的日期并将其與固定時間組合成友好的日期和時間格式
tomorrow_date=$(date -d "+1 day" +%Y-%m-%d)
start_time='01:00:00'
end_time='06:00:00'
datetime_start="$tomorrow_date $start_time"
datetime_end="$tomorrow_date $end_time"
start_point=$(date -d "$datetime_start"  +"%Y-%m-%dT%H:%M:%S%:z")
end_point=$(date -d "$datetime_end"   +"%Y-%m-%dT%H:%M:%S%:z")

# 定義正規表達式模式,抑制建立者和抑制描述或注釋
regex_pattern="module=~mysql.*"
author="admin"
comment="for test"

# 建立amtool指令
command="amtool silence add '$regex_pattern' --start='$start_point' --end='$end_point' -a '$author' -c '$comment'"

# 運作amtool指令
echo "Running command: $command"
eval "$command"           
使用api方式
#author len
#This script for create alertmanager silence every day api!
# shell 占位符, 每天淩晨1點到5點mysql告警靜默

AlertmanagerUrl="http://10.2.0.10:9093/api/v2/silences"
SILEBCE_DATA_TEL='{"matchers":[{"name":"alertname","value":"UnusualDiskIOutil","isRegex":false,"isEqual":true}],"startsAt":"%sT17:00:00.000Z","endsAt":"%sT21:00:00.000Z","createdBy":"admin","comment":"mysql_silence","id":null}'

#SILEBCE_MYSQL_TEL='{"matchers":[{"name":"module","value":"mysql.*","isRegex":true}],"startsAt":"%sT17:00:00.000Z","endsAt":"%sT21:00:00.000Z","createdBy":"admin","comment":"mysql_silence","id":null}'
SILEBCE_MYSQL_TEL='{"matchers":[{"name":"module","value":"mysql.*","isRegex":true}],"startsAt":"%sT08:00:00.000Z","endsAt":"%sT09:00:00.000Z","createdBy":"admin","comment":"mysql_silence","id":null}'

TODAY=$(date +%Y-%m-%d)
SILEBCE_DATA=`printf ${SILEBCE_DATA_TEL} ${TODAY} ${TODAY}`
SILEBCE_MYSQL=`printf ${SILEBCE_MYSQL_TEL} ${TODAY} ${TODAY}`


echo ${SILEBCE_MYSQL}

function createSilence() {
    curl "${AlertmanagerUrl}" -H "Content-Type: application/json"  \
  --data "${SILEBCE_DATA}" \
  --compressed \
  --insecure
}

function createMysqlSilence() {
    curl "${AlertmanagerUrl}" -H "Content-Type: application/json"  \
  --data "${SILEBCE_MYSQL}" \
  --compressed \
  --insecure
}

createSilence
createMysqlSilence           

注意,這邊使用的主備模式,故原則上兩個 Alertmanager 節點都需要建立一樣的周期告警抑制, 這樣才能保證,主節點挂了後, 從節點沒有對應的抑制規則造成大量的告警資訊。

繼續閱讀