Vấn Đề Alert Nhiễu Mà Không Ai Cảnh Báo Bạn
Bạn cài Prometheus, kết nối vài rules, và mọi thứ trông có vẻ ổn — cho đến khi một sự cố mạng nhỏ kích hoạt 200 alert lúc 3 giờ sáng. Điện thoại bạn rung liên tục. Bạn tắt hết alert chỉ để ngủ tiếp. Sáng hôm sau, một sự cố thật sự đã bị chôn vùi trong đống nhiễu và bạn bỏ lỡ nó.
Đây là lỗi Alertmanager phổ biến nhất trong môi trường production. Monitoring stack về mặt kỹ thuật là đúng, nhưng alerting được cấu hình như một suy nghĩ thứ yếu. Một file alertmanager.yml trần trụi với một receiver duy nhất và không có routing logic sẽ phá nát lịch trực on-call của bạn trong vòng một tuần.
Giải pháp không phải là ít alert hơn — mà là gửi alert thông minh hơn. Alertmanager cung cấp ba công cụ cốt lõi: routing, grouping và inhibition. Kết hợp lại, chúng biến số lượng alert thô thành các thông báo có thể hành động, giàu ngữ cảnh, đánh thức đúng người vì đúng lý do.
So Sánh Cách Tiếp Cận: Naive và Alertmanager Có Cấu Trúc
Trước khi đụng vào config, hãy hiểu rõ bạn đang lựa chọn giữa những gì.
Cấu Hình Naive — Một Receiver Duy Nhất, Không Có Logic
route:
receiver: 'slack-default'
receivers:
- name: 'slack-default'
slack_configs:
- api_url: 'https://hooks.slack.com/...'
Chuyển mọi alert đến một channel. Mất năm phút để cài đặt. Sụp đổ ngay khi bạn có một tuần bận rộn.
Cấu Hình Có Cấu Trúc — Routing Tree với Grouped Delivery
route:
group_by: ['alertname', 'cluster', 'service']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receiver: 'default'
routes:
- match:
severity: critical
receiver: 'pagerduty-critical'
- match:
team: platform
receiver: 'telegram-platform'
inhibit_rules:
- source_match:
severity: critical
target_match:
severity: warning
equal: ['alertname', 'cluster']
Alert được nhóm lại, loại bỏ trùng lặp, định tuyến theo label, và nhiễu warning bị triệt tiêu khi critical đã kích hoạt. Đây là diện mạo của môi trường production thực sự.
Ưu và Nhược Điểm của Mỗi Cách Tiếp Cận
- Naive — Ưu: không tốn công cấu hình. Nhược: alert storms, không phân chia ưu tiên, kiệt sức on-call trong vài ngày.
- Có cấu trúc — Ưu: giảm nhiễu, routing theo team, đường leo thang rõ ràng. Nhược: cần lập kế hoạch trước và kỷ luật label xuyên suốt các alert rules.
Routing kém không chỉ gây khó chịu — nó còn làm xói mòn niềm tin. Khi các kỹ sư nhận ra rằng alert thường là nhiễu, họ sẽ ngừng kiểm tra. Lúc đó monitoring stack của bạn chỉ là hình thức, không còn là bảo vệ nữa.
Cách Cài Đặt Khuyến Nghị: Thiết Kế Labels-First
Alertmanager định tuyến dựa trên labels. Những labels đó đến từ các alerting rules của Prometheus — vì vậy hãy làm đúng chúng trước, trước khi bạn chạm vào Alertmanager config.
# Trong file rules của Prometheus
groups:
- name: app.rules
rules:
- alert: HighErrorRate
expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.05
for: 2m
labels:
severity: critical
team: backend
service: api
annotations:
summary: "Tỷ lệ lỗi cao trên {{ $labels.service }}"
description: "Tỷ lệ lỗi là {{ $value | humanizePercentage }}"
Khi severity, team và service được đặt nhất quán trên mọi rule, routing tree của bạn trở nên có thể dự đoán và dễ bảo trì. Bỏ qua những labels này và routing trở thành trò đoán mò.
Hướng Dẫn Triển Khai
Bước 1 — Cài Đặt và Khởi Động Alertmanager
# Tải về
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
cd alertmanager-0.27.0.linux-amd64
# Khởi động với config
./alertmanager --config.file=alertmanager.yml --storage.path=/var/lib/alertmanager
Sau đó cho Prometheus biết nơi tìm Alertmanager bằng cách thêm vào prometheus.yml:
alerting:
alertmanagers:
- static_configs:
- targets: ['localhost:9093']
Bước 2 — Cấu Hình Routing
Routing tree đánh giá các route từ trên xuống dưới và dừng ở match đầu tiên. Đặt continue: true trên một route để gửi đến nhiều receiver. Đặt các matcher cụ thể nhất ở trên cùng.
route:
receiver: 'default-receiver'
group_by: ['alertname', 'cluster']
group_wait: 30s
group_interval: 5m
repeat_interval: 12h
routes:
# Alert critical chuyển đến PagerDuty để escalate ngay
- match:
severity: critical
receiver: 'pagerduty'
# Team platform nhận thông báo Telegram
- match:
team: platform
receiver: 'telegram-platform'
# Alert database tách riêng
- match_re:
service: 'postgres|mysql|redis'
receiver: 'telegram-db'
Bước 3 — Cấu Hình Grouping
Grouping là thứ ngăn alert storm lúc 3 giờ sáng. Khi một node bị down và 50 alert kích hoạt đồng thời, Alertmanager gom chúng thành một thông báo thay vì 50 tin nhắn riêng lẻ.
Ba cài đặt kiểm soát hành vi này:
group_wait: 30s— Thời gian chờ trước khi gửi thông báo đầu tiên cho một nhóm mới. Cho các alert liên quan thời gian để đến cùng nhau. Giá trị mặc định 30 giây hoạt động tốt trong thực tế.group_interval: 5m— Thời gian chờ trước khi gửi cập nhật khi có alert mới gia nhập nhóm hiện có. Năm phút là điểm khởi đầu hợp lý cho hầu hết các team.repeat_interval: 12h— Tần suất thông báo lại về một alert đang kích hoạt. Dùng 1h cho critical, 4–12h cho warning. Repeat 1 phút trên một warning nghĩa là cứ mỗi phút gửi một lần cho đến khi ai đó sửa — tránh điều này.
Bước 4 — Cấu Hình Inhibition Rules
Inhibition tắt tiếng các alert ưu tiên thấp hơn khi một alert mức độ cao hơn cho cùng hệ thống đã kích hoạt. Đây là đòn bẩy giảm nhiễu mạnh nhất mà Alertmanager có.
inhibit_rules:
# Tắt warning khi critical đang active cho cùng service
- source_match:
severity: 'critical'
target_match:
severity: 'warning'
equal: ['alertname', 'cluster', 'service']
# Tắt tất cả alert app khi toàn bộ node bị down
- source_match:
alertname: 'NodeDown'
target_match_re:
alertname: '.*'
equal: ['instance']
Rule thứ hai là thứ mọi người luôn ước mình đã thêm sớm hơn. Khi NodeDown kích hoạt cho một host, mọi alert phát sinh từ host đó — đĩa đầy, CPU cao, service down — đều bị tắt tự động. Sửa node, mọi thứ tự giải quyết. Không cần tắt thủ công.
Bước 5 — Tích Hợp với Telegram
Bắt đầu bằng cách tạo bot qua @BotFather trong Telegram và lấy token. Sau đó tìm chat ID của bạn: gửi bất kỳ tin nhắn nào đến bot, truy cập https://api.telegram.org/bot<TOKEN>/getUpdates, và tìm trường chat.id trong JSON response. Group có ID âm.
receivers:
- name: 'telegram-platform'
telegram_configs:
- bot_token: 'YOUR_BOT_TOKEN'
chat_id: -1001234567890
message: |
{{ range .Alerts }}
*[{{ .Status | toUpper }}]* {{ .Labels.alertname }}
Dịch vụ: {{ .Labels.service }}
{{ .Annotations.summary }}
{{ end }}
parse_mode: 'Markdown'
Trường message sử dụng Go templating. Hãy giữ nó ngắn gọn — Telegram cắt bớt tin nhắn quá 4096 ký tự, và những đống alert dày đặc thì không đọc được trên mobile. Một dòng mỗi alert với severity và tên service là đủ ngữ cảnh để hành động.
Bước 6 — Tích Hợp với PagerDuty
PagerDuty xử lý việc leo thang on-call cho critical. Trong PagerDuty, vào service → tab Integrations → Add an integration → chọn Prometheus. Sao chép routing key bạn nhận được.
receivers:
- name: 'pagerduty'
pagerduty_configs:
- routing_key: 'YOUR_PAGERDUTY_ROUTING_KEY'
description: '{{ .GroupLabels.alertname }} — {{ .GroupLabels.cluster }}'
severity: '{{ if eq .CommonLabels.severity "critical" }}critical{{ else }}warning{{ end }}'
details:
firing: '{{ template "pagerduty.default.instances" .Alerts.Firing }}'
resolved: '{{ template "pagerduty.default.instances" .Alerts.Resolved }}'
PagerDuty loại bỏ trùng lặp bằng dedup_key được tạo từ group labels. Một alert đang kích hoạt và trạng thái resolved của nó liên kết tự động — không có incident nào bị bỏ lơ sau khi sự cố được giải quyết.
Bước 7 — Kiểm Tra với amtool
Đừng bao giờ đẩy alertmanager.yml mới mà không validate trước. amtool đi kèm phát hiện lỗi routing trước khi chúng đến production.
# Kiểm tra cú pháp config
amtool check-config alertmanager.yml
# Test routing — xem alert sẽ đến receiver nào
amtool config routes test --config.file=alertmanager.yml \
severity=critical team=backend service=api
# Gửi test alert thủ công
amtool alert add alertname=TestAlert severity=critical service=api \
--annotation=summary="Test alert từ amtool" \
--alertmanager.url=http://localhost:9093
Những Lỗi Thường Gặp Cần Tránh
- Bỏ qua
group_by: Tất cả alert gộp thành một thông báo khổng lồ. Luôn group theo ít nhấtalertnamevà một topology label nhưclusterhoặcinstance. - Đặt
repeat_intervalquá thấp: Một phút trên một warning alert nghĩa là một thông báo mỗi phút cho đến khi ai đó sửa. 4–12 giờ là khoảng hợp lý cho alert không critical. - Quên
equaltrong inhibit rules: Nếu thiếu, một critical trên một host sẽ tắt warning trên mọi host khác trong cluster. Luôn giới hạn phạm vi inhibition bằng labels phù hợp. - Một receiver cho tất cả: On-call database và on-call ứng dụng là những người khác nhau với ngữ cảnh khác nhau. Hãy route riêng từ ngày đầu tiên.
File alertmanager.yml Đầy Đủ
global:
resolve_timeout: 5m
route:
receiver: 'default-receiver'
group_by: ['alertname', 'cluster', 'service']
group_wait: 30s
group_interval: 5m
repeat_interval: 12h
routes:
- match:
severity: critical
receiver: 'pagerduty'
- match:
team: platform
receiver: 'telegram-platform'
- match_re:
service: 'postgres|mysql|redis'
receiver: 'telegram-db'
inhibit_rules:
- source_match:
severity: 'critical'
target_match:
severity: 'warning'
equal: ['alertname', 'cluster', 'service']
- source_match:
alertname: 'NodeDown'
target_match_re:
alertname: '.*'
equal: ['instance']
receivers:
- name: 'default-receiver'
telegram_configs:
- bot_token: 'YOUR_BOT_TOKEN'
chat_id: -1001234567890
message: '[{{ .Status | toUpper }}] {{ .GroupLabels.alertname }}'
- name: 'telegram-platform'
telegram_configs:
- bot_token: 'YOUR_BOT_TOKEN'
chat_id: -1009876543210
message: |
{{ range .Alerts }}
*{{ .Status | toUpper }}* — {{ .Labels.alertname }}
{{ .Annotations.summary }}
{{ end }}
parse_mode: 'Markdown'
- name: 'telegram-db'
telegram_configs:
- bot_token: 'YOUR_BOT_TOKEN'
chat_id: -1001111111111
message: '[DB] {{ .GroupLabels.alertname }} trên {{ .GroupLabels.instance }}'
- name: 'pagerduty'
pagerduty_configs:
- routing_key: 'YOUR_PAGERDUTY_ROUTING_KEY'
description: '{{ .GroupLabels.alertname }} — {{ .GroupLabels.cluster }}'

