深色模式
值班疲劳治理
摘要:疲劳不是主观感受,可以用"夜间被叫次数、连续响应时长、无效告警占比"三个数字衡量。本文给出计算这些指标的查询与脚本,以及对应的降噪、夜间保护与轮值上限措施。
适用环境
bash
# 数据来自告警平台记录;自建时可用 Alertmanager 日志近似统计
ls -1 /var/log/alertmanager/ 2>/dev/null | tail
command -v sqlite3 >/dev/null || echo "无 sqlite3 时用 awk 统计"1
2
3
2
3
操作步骤
第 1 步:先量化疲劳
bash
# 建一张极简告警记录表
sqlite3 oncall.db <<'SQL'
CREATE TABLE IF NOT EXISTS pages(
ts TEXT, severity TEXT, acked INTEGER, night INTEGER, service TEXT
);
SQL
# 统计:近 30 天每人夜间(22:00-08:00)被叫次数
sqlite3 oncall.db <<'SQL'
SELECT substr(ts,1,10) AS day,
SUM(night) AS night_pages,
SUM(acked=0) AS unacked
FROM pages
WHERE ts >= datetime('now','-30 day')
GROUP BY day ORDER BY night_pages DESC LIMIT 10;
SQL1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
第 2 步:设定红线阈值
| 指标 | 红线 |
|---|---|
| 单人每周夜间被叫 | > 3 次 |
| 单周值班总时长 | > 48 小时(含加班) |
| 无效/噪声告警占比 | > 30% |
| 连续值班天数 | > 7 天 |
bash
# 超标即告警到负责人,而不是让值班人自己扛
sqlite3 oncall.db "SELECT CASE WHEN COUNT(*)>3 THEN 'ALERT: 夜间打扰超标' ELSE 'OK' END FROM pages WHERE night=1 AND ts >= datetime('now','-7 day');"1
2
2
第 3 步:降噪是第一优先级
yaml
# 合并重复告警:按服务聚合,避免一次故障 20 条通知
route:
group_by: ['alertname', 'service']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
# 抑制:主服务挂了,抑制其下游告警
inhibit_rules:
- source_matchers: ['severity="critical"', 'service="db"']
target_matchers: ['severity="warning"']
equal: ['env']1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
第 4 步:夜间保护
yaml
# 非 Sev1 在夜间不呼叫,改为次日汇总
- matchers: ['severity="warning"']
active_time_intervals: ['business-hours']
receiver: 'oncall-primary'
- matchers: ['severity="warning"']
receiver: 'morning-digest'
time_intervals:
- name: business-hours
time_intervals:
- times: [{ start_time: '09:00', end_time: '22:00' }]
weekdays: ['monday:friday']1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
第 5 步:轮值硬约束
bash
# 排班生成时强制:连续值班 ≤ 7 天,且每轮后至少 1 周不值班
cat > fatigue-guard.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
# 用法: ./fatigue-guard.sh person consecutive_days
p=$1; d=$2
[ "$d" -gt 7 ] && { echo "$p 连续 $d 天,违反上限"; exit 1; }
echo "$p OK"
EOF
chmod +x fatigue-guard.sh && ./fatigue-guard.sh alice 51
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
验证
bash
# 1. 噪声占比下降:统计 14 天内未 ACK 的告警比例
sqlite3 oncall.db "SELECT printf('%.1f%%', 100.0*SUM(acked=0)/COUNT(*)) FROM pages WHERE ts>=datetime('now','-14 day');"
# 2. 夜间打扰次数在上周已达标
sqlite3 oncall.db "SELECT COUNT(*) FROM pages WHERE night=1 AND ts>=datetime('now','-7 day');"
# 3. Alertmanager 抑制规则生效
amtool check-config /etc/alertmanager/alertmanager.yml1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
常见坑
只谈"抗压能力"不谈指标
没有数字的疲劳讨论会变成抱怨。先把夜间被叫次数统计出来,再谈改进。
降噪等于关告警
把不想看的告警直接静音是掩盖问题。正确做法是修根因(提升阈值、修 flapping),再合并通知。
长期一人值守小团队
2 人轮值没有退路,任何休假都会变成风险。低于 4 人应缩小值班范围(只保核心服务)或引入跨团队兜底。