告警策略与On-Call实践
1. 告警分级
| 级别 | 含义 | 响应时间 | 通知方式 |
|---|---|---|---|
| P0 Critical | 服务不可用、数据丢失 | 5 分钟内 | 电话 + 短信 + 群 |
| P1 High | 严重降级、部分不可用 | 15 分钟内 | 短信 + 群 |
| P2 Warning | 性能下降、资源预警 | 1 小时内 | IM 群 |
| P3 Info | 信息性、趋势异常 | 工作时间 | 邮件 |
2. 好告警的特征
- 可执行:收到告警知道做什么(有 runbook 链接)
- 有意义:反映真实用户影响
- 不重复:同一问题不连续报
- 有上下文:含 namespace / pod / url / 当前值
反面:告警疲劳 = 大量无意义告警 → 全员屏蔽 → 真出事没人看。
3. 核心告警规则
3.1 可用性
- alert: ServiceDown
expr: up{job="frontend"} == 0
for: 1m
labels: { severity: critical }
annotations:
summary: "}} $labels.instance }} 下线"
runbook: "https://wiki/runbooks/service-down"
3.2 错误率
- alert: HighErrorRate
expr: |
sum(rate(http_requests_total{status=~"5..", namespace="frontend"}[5m]))
/ sum(rate(http_requests_total{namespace="frontend"}[5m])) > 0.01
for: 5m
labels: { severity: warning }
3.3 延迟
- alert: HighP95Latency
expr: |
histogram_quantile(0.95, sum by (le) (
rate(http_request_duration_seconds_bucket{namespace="frontend"}[5m])
)) > 2
for: 10m
3.4 资源
- alert: HighMemory
expr: |
container_memory_working_set_bytes{namespace="frontend"}
/ container_spec_memory_limit_bytes > 0.85
for: 5m
- alert: DiskAlmostFull
expr: |
(node_filesystem_avail_bytes / node_filesystem_size_bytes) < 0.15
for: 10m
3.5 证书过期
- alert: CertExpiring
expr: probe_ssl_earliest_cert_expiry - time() < 30 * 86400
for: 1h
labels: { severity: warning }
4. Alertmanager 路由
route:
receiver: default
group_by: [alertname, namespace]
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
routes:
- matchers: [severity="critical"]
receiver: pager
repeat_interval: 15m
- matchers: [severity="warning", team="frontend"]
receiver: frontend-channel
- matchers: [alertname="Watchdog"]
receiver: /dev/null
receivers:
- name: pager
pagerduty_configs:
- service_key: '<key>'
webhook_configs:
- url: 'https://hooks.feishu.cn/...'
- name: frontend-channel
slack_configs:
- api_url: 'https://hooks.slack.com/...'
channel: '#frontend-alerts'
title: '}} .GroupLabels.alertname }}'
text: '}} range .Alerts }}}} .Annotations.summary }}\n}} end }}'
inhibit_rules:
- source_matchers: [severity="critical"]
target_matchers: [severity="warning"]
equal: [alertname, namespace]
inhibit_rules:critical 触发时抑制同名 warning(减少噪声)。
5. On-Call 轮值
5.1 工具
| 工具 | 特点 |
|---|---|
| PagerDuty | 最成熟,贵 |
| OpsGenie(Atlassian) | 集成 Jira |
| Grafana OnCall(开源) | 免费自建 |
| 飞书/钉钉值班机器人 | 国内轻量 |
5.2 排班
- 周轮:每人一周(7×24 不现实,跨时区分)
- 主 / 副:主值班处理,副兜底
- 升级策略:5 分钟主不响应 → 自动转副 → 10 分钟无响应 → leader
5.3 值班职责
- 响应:收到告警 5 分钟内确认
- 定级:判断 P0-P3
- 处置:能解决就解决,不能升级
- 沟通:影响用户的实时更新状态(内部群 / 状态页)
- 复盘:重大事故写 postmortem
6. Postmortem(事后复盘)
## 事故报告 #42
### 概况
- 时间:2026-06-18 14:00 - 14:35 (35 分钟)
- 影响:前端 API 返回 502,约 5000 用户受影响
- 级别:P1
### 时间线
- 14:00 发布新版本
- 14:02 502 告警触发
- 14:05 值班人员确认
- 14:10 定位根因:新版本 DB 查询死锁
- 14:15 执行回滚
- 14:20 回滚完成,502 率下降
- 14:35 全部恢复
### 根因
新版本引入的复杂查询在并发场景下导致 DB 行锁升级为表锁。
### 教训
1. 复杂查询上线前必须压测
2. DB 慢查询监控阈值从 5s 降到 2s
3. 灰度比例从 10% 开始而非直接全量
### Action Items
- [ ] 加 DB 死锁告警 @Bob 本周
- [ ] CI 加 SQL review @Alice 本周
- [ ] 灰度流程写入规范 @Team Lead 下周
无责文化:关注系统改进而非追责。
7. 状态页
对外公示服务状态:
- Statuspage.io(Atlassian)
- Instatus
- 自建:betteruptime.com / cachet
维护中 / 部分故障 / 重大故障 → 用户自查不用反复问客服。
8. 常见反模式
- 所有告警 critical:on-call 全屏蔽
- 告警没 runbook:值班人员不知道怎么处理
- repeat_interval 太短:同一问题每 5 分钟发一次
- 不做 inhibit:critical + warning 同时报
- 值班没补偿:半夜被叫没调休,团队抵触
- postmortem 追责:以后人人隐瞒
- 告警发到大群:没人觉得自己该处理
- 不做值班交接:上手的人不知道当前未解决的问题