Prometheus Alertmanager Silences và Inhibition Rules: Giảm Alert Noise trong hệ thống production

Monitoring tutorial - IT technology blog
Monitoring tutorial - IT technology blog

Bối cảnh: Khi cảnh báo nhiều hơn sự cố thực tế

Alert fatigue là vấn đề thực tế mình gặp khi mới setup monitoring. Đã tune threshold không dưới 10 lần trước khi nhận ra rằng vấn đề không phải ở threshold — mà ở cách Alertmanager được cấu hình. Mỗi lần có sự cố, hàng chục cảnh báo đổ về cùng lúc: CPU high, memory high, response time tăng, health check fail — tất cả từ cùng một nguyên nhân. Sau vài tuần, cả team bắt đầu ignore Slack channel monitoring.

Thì ra Alertmanager có sẵn hai thứ xử lý đúng chỗ này:

  • Silences: Tắt tạm thời một nhóm cảnh báo trong khoảng thời gian xác định — dùng khi bạn biết trước sẽ có downtime hoặc đang trong maintenance
  • Inhibition Rules: Tự động chặn các cảnh báo phụ khi cảnh báo chính đã kích hoạt — giảm symptom alerts khi đã có root cause alert

Bài này đi thẳng vào hai tính năng đó. Giả sử bạn đã có Alertmanager đang chạy với receiver cơ bản rồi.

Cài đặt amtool — CLI quản lý Alertmanager

amtool đi kèm với bộ cài Alertmanager và là công cụ chính để tương tác từ terminal. Nếu chưa có:

# Tải Alertmanager (amtool đi kèm trong gói)
wget https://github.com/prometheus/alertmanager/releases/download/v0.27.0/alertmanager-0.27.0.linux-amd64.tar.gz
tar xvf alertmanager-0.27.0.linux-amd64.tar.gz
sudo mv alertmanager-0.27.0.linux-amd64/amtool /usr/local/bin/

# Tạo config mặc định cho amtool (tránh phải gõ URL mỗi lần)
mkdir -p ~/.config/amtool
cat > ~/.config/amtool/config.yml <<EOF
alerting.url: http://localhost:9093
EOF

# Kiểm tra kết nối
amtool alert query

Cấu hình chi tiết

Silences — Tắt cảnh báo có chủ đích

Cách đơn giản nhất là qua UI tại http://your-server:9093, tab SilencesNew Silence. Nhưng trong thực tế, mình dùng amtool nhiều hơn vì có thể tích hợp vào script.

# Silence tất cả alert của service web trong 2 giờ
amtool silence add \
  --duration=2h \
  --comment="Deploy v2.1.0 — expected restart" \
  alertname=~".+" \
  service="web"

# Xem danh sách silence đang active
amtool silence query

# Expire silence ngay khi deploy xong sớm hơn dự kiến
amtool silence expire <silence-id>

Hiện tại mình integrate amtool vào CI/CD pipeline. Trước mỗi deploy, script tự tạo silence 30 phút. Sau khi health check pass, expire ngay — tránh hàng chục false positive alert mỗi lần release:

#!/bin/bash
# deploy-with-silence.sh

SILENCE_ID=$(amtool silence add \
  --duration=30m \
  --comment="CI/CD deploy $(git rev-parse --short HEAD)" \
  environment="production" \
  service="api" \
  --output=json | jq -r '.silenceID')

echo "Silence created: $SILENCE_ID"

# Chạy deploy
./deploy.sh

# Expire silence sau khi health check pass
amtool silence expire "$SILENCE_ID"
echo "Silence expired"

Lưu ý quan trọng: Luôn điền trường comment khi tạo silence. Hai tuần sau bạn sẽ không nhớ tại sao silence đó tồn tại, và người khác trong team càng không biết.

Inhibition Rules — Logic tự động chặn alert thứ cấp

Tính năng này bị bỏ qua nhiều hơn mình nghĩ, dù nó mới là thứ xử lý được tận nguồn vấn đề alert noise. Nguyên lý đơn giản: nếu alert A đang active, chặn luôn tất cả alert B có cùng label chỉ định.

Ví dụ kinh điển nhất: Node down thì mọi service trên node đó đương nhiên cũng down. Không cần nhận 20 alert riêng lẻ — 1 alert NodeDown là đủ để biết phải làm gì.

Thêm vào file /etc/alertmanager/alertmanager.yml:

inhibit_rules:
  # Khi node down, chặn tất cả alert severity warning/critical từ node đó
  - source_matchers:
      - alertname = "NodeDown"
    target_matchers:
      - severity =~ "warning|critical"
    equal:
      - instance

  # Critical alert chặn warning alert cùng service (tránh spam warning khi critical đã fire)
  - source_matchers:
      - severity = "critical"
    target_matchers:
      - severity = "warning"
    equal:
      - alertname
      - namespace
      - service

  # Database down chặn application error alerts (chặn symptom khi root cause đã rõ)
  - source_matchers:
      - alertname = "DatabaseDown"
      - severity = "critical"
    target_matchers:
      - alertname =~ "HighErrorRate|SlowResponse|ServiceUnavailable"
    equal:
      - environment

Giải thích từng field:

  • source_matchers: Điều kiện của alert “cha” — alert gây ra inhibition
  • target_matchers: Điều kiện của alert bị chặn
  • equal: Các label phải có giá trị giống nhau giữa source và target — đây là cách Alertmanager biết hai alert thuộc cùng instance/service

Ví dụ production cho Kubernetes cluster

Config dưới đây là cấu hình mình đang chạy thực tế trên môi trường Kubernetes multi-cluster:

inhibit_rules:
  # Cluster network partition chặn node-level alerts
  - source_matchers:
      - alertname = "ClusterNetworkPartition"
    target_matchers:
      - alertname =~ "NodeDown|NodeUnreachable"
    equal:
      - cluster

  # Node not ready chặn pod alerts trên node đó
  - source_matchers:
      - alertname = "KubeNodeNotReady"
    target_matchers:
      - alertname =~ "KubePodCrashLooping|KubePodNotReady|KubeDeploymentReplicasMismatch"
    equal:
      - node
      - cluster

  # PVC full chặn application write error (chặn symptom khi storage là root cause)
  - source_matchers:
      - alertname = "KubePersistentVolumeFillingUp"
      - severity = "critical"
    target_matchers:
      - alertname = "AppWriteError"
    equal:
      - namespace
      - persistentvolumeclaim

Một trick khác mình dùng: tạo “maintenance window alert” để tự động inhibit thay vì phải tạo silence thủ công. Cụ thể, định nghĩa một Prometheus recording rule tên MaintenanceWindow với label environment="production", chỉ active trong giờ bảo trì. Inhibition rule sau đó tự chặn mọi warning/info alert trong khoảng đó — không cần động tay.

Kiểm tra và Monitoring

Xác nhận inhibition rules hoạt động đúng

# Xem tất cả alert đang active
amtool alert query

# Xem cả alert bị inhibit và silence
amtool alert query --silenced --inhibited

# Filter theo label cụ thể
amtool alert query severity=critical environment=production

# Validate file config trước khi reload
amtool check-config /etc/alertmanager/alertmanager.yml

Khi alert bị chặn không đúng ý, dùng API trực tiếp để debug:

# Xem alert kèm lý do bị inhibit
curl -s 'http://localhost:9093/api/v2/alerts?inhibited=true&silenced=true' | \
  jq '.[] | {alertname: .labels.alertname, state: .status.state, inhibitedBy: .status.inhibitedBy}'

Metrics Alertmanager để theo dõi hiệu quả

Scrape metrics của chính Alertmanager — cách nhanh nhất để Prometheus tự theo dõi nó:

# prometheus.yml
scrape_configs:
  - job_name: 'alertmanager'
    static_configs:
      - targets: ['localhost:9093']

Các metric hữu ích nhất:

  • alertmanager_alerts{state="active"} — số alert đang active
  • alertmanager_alerts{state="suppressed"} — số alert bị chặn (inhibit + silence cộng lại)
  • alertmanager_silences{state="active"} — số silence đang hoạt động
  • alertmanager_notifications_total — tổng notification đã gửi
  • alertmanager_notifications_failed_total — số notification thất bại

Query để theo dõi tỷ lệ suppression trên Grafana:

# Tỷ lệ alert bị suppress so với tổng
alertmanager_alerts{state="suppressed"} / ignoring(state) sum without(state)(alertmanager_alerts)

Khi tỷ lệ này tăng sau khi thêm inhibition rules, đó là dấu hiệu tốt. Team nhận ít thông báo hơn, nhưng mỗi cái đều đáng để nhìn vào.

Một vài điểm cần chú ý từ thực tế

Sau nhiều lần chỉnh sửa config, mình rút ra:

  • Field equal cần tồn tại trong cả source và target — nếu một trong hai alert không có label đó, rule sẽ không match và inhibition không hoạt động. Đây là lỗi mình mất khá nhiều thời gian debug lần đầu.
  • Tránh inhibit quá rộng — chỉ chặn những alert thực sự là symptom của source alert, không phải mọi alert từ cùng environment.
  • Reload config không cần restart: curl -X POST http://localhost:9093/-/reload là đủ.
  • Silence không phải giải pháp lâu dài — nếu phải tạo silence thường xuyên cho cùng một alert, đó là dấu hiệu threshold đang sai hoặc cần thêm inhibition rule.

Nếu bạn đã có Alertmanager cơ bản đang chạy, thêm inhibition rules chỉ mất khoảng 30 phút. Số notification mỗi ngày có thể giảm 50–70% tùy hệ thống. Quan trọng hơn: team sẽ bắt đầu để ý lại vì mỗi alert đều có lý do thực sự để ping.

Share: