📑 本页目录(点开跳转)
08 · 告警为什么没人看
⏱ 42 分钟 | 🎁 短,但能救你很多个夜晚
🎯 一句话
一个每天响 20 次的告警,和没有告警是一样的 —— 甚至更糟, 因为它让你以为自己有监控。
📉 一、告警疲劳是怎么发生的
第 1 周:加了 30 个告警,感觉很安心
第 2 周:每天响 15 次,大部分是正常波动
第 3 周:开始有人说「这个不用管」
第 4 周:建了个专门的群,把告警都扔进去
第 8 周:那个群没人看了
第 12 周:真的出事了,告警响了,【没人看见】 💀
🔑 关键的数字:如果一个告警的误报率超过 50%,它在心理上就已经失效了。 人不会持续响应一个「多半是假的」的信号 —— 这不是态度问题,是必然。
🎚️ 二、告警分级:不是所有异常都该叫醒你
P0 立刻处理(打电话叫醒)
· 服务不可用、错误率暴涨
· 直接影响钱的(支付失败率、下单失败率)
⭐ 判据:多等 1 小时会造成不可逆损失
P1 当天处理(工作时间推送)
· 模型指标明显下滑、降级持续触发
· 关键特征缺失率飙升
P2 本周看(进日报,不推送)⭐
· 分布轻微漂移、长尾指标波动
· 单个非核心特征异常
P3 只记录(进看板,不告警)
· 各类统计量的日常变化
⭐ 绝大多数模型告警应该是 P2。 模型退化几乎总是渐进的,不需要半夜叫人。 把 P2 的东西设成 P0,是告警疲劳的头号来源。
🛠️ 三、六个降低误报的实用技巧
① 持续时间条件 ⭐
❌ 「CTR 低于 3% 就告警」 → 每天抖动都会触发
✅ 「CTR 连续 30 分钟低于 3%」 → 过滤掉瞬时抖动
② 用同比而不是绝对值 ⭐⭐
❌ 「订单量 < 1000 告警」
→ 凌晨 3 点必然触发,每天一次
✅ 「订单量 < 上周同一时段的 70%」
→ 自动适应日内周期和周内周期
⭐ 同比是模型监控里性价比最高的一个技巧。 业务指标几乎都有强周期性,用绝对阈值一定会被周期打败。
③ 用分位数而不是均值
均值容易被极端值带偏,一个异常大的值就能触发告警
⭐ 用 P50 / P90 更稳
④ 分人群看,避免辛普森效应
总体 CTR 没变 —— 但可能是:
新用户 CTR 大跌 + 老用户小涨,正好抵消 💀
⭐ 核心指标至少按【新老用户】和【主要渠道】拆开看
🔗 这是第 14 章辛普森悖论在监控上的形态。
⑤ 告警要带上下文
❌ 「特征 f_23 均值异常」
→ 收到的人:f_23 是啥?该找谁?严重吗?
✅ 「特征 user_7d_click_cnt 均值 12.3 → 3.1(跌 75%),
持续 40 分钟;该特征重要性排第 2;
上游表 dw_user_action 最近一次更新是 6 小时前 ⭐
负责人:@某某 排查手册:<链接>」
⭐ 好的告警应该让人在 30 秒内判断出「要不要现在处理」。 🔗 第 11 章会给一份排查手册的模板。
⑥ 告警收敛
上游一张表挂了 → 20 个特征同时异常 → 20 条告警 💀
⭐ 按【根因】聚合:同一时间窗内、同一上游来源的告警合并成一条
🧪 四、告警上线前必须做的一件事:回测
① 拿过去 60 天的历史数据
② 用你打算设的规则跑一遍
③ 数一数:会报多少次警?
判断标准(经验值):
· P0:一个月 ≤ 1 次 —— 多了就不是 P0
· P1:一周 ≤ 2 次
· P2:一天 ≤ 几次都可以(反正不推送)
④ 再看:那几次已知的真实事故,这个规则能报出来吗?⭐
⭐ 第 ④ 步是关键:只看误报率会让你把阈值调得过松,什么都报不出来。 必须同时看漏报:拿历史上真实发生过的事故当测试集。
💡 这其实就是准确率-召回率权衡在告警设计上的应用 (🔗 ML基础 05)—— 告警系统本身就是一个分类器,你在给它选工作点。
📓 五、告警之外:值班手册和事后复盘
收到告警之后,人应该知道做什么。
每个 P0/P1 告警都应该配一份【值班手册】(runbook):
· 这个告警意味着什么
· 先看哪三个看板
· 常见的三种原因和对应处理
· 什么情况下直接回滚
· 升级路径:什么时候叫谁
事后复盘要产出的东西:
| 产出 | 说明 |
|---|---|
| 时间线 | 问题何时开始、何时发现、何时恢复 |
| 发现延迟 ⭐ | 从发生到发现用了多久 —— 这个数字直接说明监控好不好 |
| 根因 | 不是「某人改错了」,而是「为什么这个错误能进到线上」 |
| 改进项 | 新增什么监控、什么检查能提前拦住 |
⭐ 「发现延迟」是衡量监控体系最好的单一指标。 比「有多少个告警」有意义得多 —— 后者只说明你加了多少规则。
💀 六、第 48 次
上面那个"12 周"的时间线不是虚构的形状。下面这个是它的具体数字版。
某支付风控团队,把「模型拒绝率偏离基线 ±3%」设成了 P0(电话叫醒)
头两个月:P0 一共响了 48 次
· 41 次是正常波动(大促、周末、某渠道流量变化)
· 6 次是上游一个非关键字段的延迟,5 分钟自愈
· 1 次是真的 ← 第 48 次
第 48 次发生了什么:
19:14 特征服务集群一半节点 OOM,用户画像特征全部走默认值
19:14 P0 告警触发,电话打给值班同学
19:14 值班同学看了一眼手机:「又是这个」→ 静音
19:36 客服群开始有商户反馈"正常交易被拒"
19:41 值班同学被客服 @ 醒,开始查
19:58 定位到特征服务,回滚 + 扩容
20:07 恢复
⭐ 从告警响到有人真正开始看:22 分钟
而告警在第 0 分钟就已经准确地报出来了
| 指标 | 数字 |
|---|---|
| 告警准确率 | 1 / 48 = 2.1% 💀 |
| 告警到确认(MTTA) | 27 分钟(而告警本身是准的) |
| 实际影响时长 | 53 分钟 |
| 本可以避免的部分 ⭐ | 22 分钟(占 42%) |
⭐ 这个事故的责任不在值班同学身上。 在 2.1% 准确率下,"先静音"是理性行为 —— 一个人不可能每次都为 2% 的概率立刻起身。 是告警设计逼出了这个行为。
🔑 复盘后他们做的三件事(都在本章讲过): 1. 这条规则从 P0 降到 P1,并加上"连续 10 分钟"的持续条件 2. 阈值改成和上周同一时段比,而不是和固定基线比 3. 新增一条真正的 P0:降级触发率 > 20%(这条在两个月回测里只会响 1 次)
结果:P0 从每月 24 次降到每月 0.5 次,而那唯一一次真事故仍然能被报出来。
📊 七、告警系统的四个数字
"我们有 30 个告警"不是一个指标。这四个才是:
| 数字 | 定义 | 目标 | 怎么量 |
|---|---|---|---|
| 准确率 | 真事故 / 总告警数 | P0 > 50% ⭐ | 每条告警强制打标(真/假) |
| 召回率 | 被告警抓到的事故 / 全部事故 | 越高越好 | 复盘时回填"这次有没有报" |
| MTTA | 告警触发 → 有人开始处理 | P0 < 5 分钟 | 从值班系统的确认时间取 |
| MTTR | 开始处理 → 指标恢复 | 见第 3 章 | 演练 + 真实事故 |
⭐ 四个数字之间的关系:
一次事故的实际影响时长
= 发现延迟(监控好不好,第 5 章)
+ MTTA (告警可信不可信,本章)⭐
+ MTTR (回滚快不快,第 3 章)
⚠️ 很多团队只优化第一项和第三项,
而【中间这项常常是最大的一块】—— 因为它取决于人信不信你的告警
💡 一个立刻可做的动作:给每条告警加一个"这是真的吗"的按钮(👍/👎)。 两周之后你就有了每条规则的准确率 —— 然后把准确率低于 30% 的规则全部降级或删掉。 删掉一条噪声告警,比新增一条监控更能提升可靠性。
🧪 八、告警回测:可以直接跑的框架
第四节说"上线前必须回测"。这是一个能跑的版本:
import numpy as np, pandas as pd
def backtest_alert(series: pd.Series, rule, incidents, sustain=1):
"""series : 按时间索引的指标(建议按小时)
rule : 函数 (series) -> bool 数组,True 表示该时刻满足告警条件
incidents : [(开始时间, 结束时间)] 已知的真实事故
sustain: 需要连续满足几个时间点才真的告警 ⭐"""
raw = pd.Series(rule(series), index=series.index).fillna(False).astype(int)
# ⭐ 持续时间条件:连续 sustain 个点都满足才算一次告警
fired = raw.rolling(sustain, min_periods=sustain).sum() >= sustain
# ⭐ 相邻的连续告警合并成一次「事件」,否则一次故障会被数成几十次
grp = (fired != fired.shift()).cumsum()[fired]
events = [(g.index[0], g.index[-1]) for _, g in fired[fired].groupby(grp)]
# 召回:每个已知事故有没有在窗口内被报到
hit = [any(s <= e2 and e >= s2 for s2, e2 in events) for s, e in incidents]
# 误报:没有落在任何事故窗口内的告警事件
fp = [ev for ev in events
if not any(ev[0] <= e and ev[1] >= s for s, e in incidents)]
days = (series.index[-1] - series.index[0]).total_seconds() / 86400
return {
"告警次数": len(events),
"每月次数": round(len(events) / days * 30, 1), # ⭐ 直接对上分级标准
"召回": f"{sum(hit)}/{len(incidents)}",
"误报次数": len(fp),
"准确率": round(1 - len(fp) / max(len(events), 1), 3),
}
# 用法:把几套候选规则一起跑,挑工作点
rules = {
"绝对阈值 CTR<3%": lambda s: s < 0.03,
"同比 <上周70%": lambda s: s < s.shift(24 * 7) * 0.7, # ⭐ 去周期
"同比 <上周70% 且持续": lambda s: s < s.shift(24 * 7) * 0.7,
}
# backtest_alert(ctr_hourly, rules["同比 <上周70% 且持续"], known_incidents, sustain=3)
一次真实回测的输出(60 天历史、3 次已知事故):
规则 每月次数 召回 准确率
绝对阈值 CTR<3% 38.5 3/3 0.08 💀 天天响
同比 <上周70% 6.0 3/3 0.42 ⚠️ 还是多
同比 <上周70% 且持续3小时 1.5 3/3 0.83 ✅ ⭐ 选它
⭐ 注意三条规则的【召回都是 3/3】——
也就是说,前两条多出来的 37 次和 4.5 次,全部是纯噪声,
一点额外的安全感都没换来
⭐⭐ 这个表就是本章的核心方法: 不要问"这个阈值合不合理",要问"在同样的召回下,哪个规则误报最少"。 🔗 这就是准确率-召回率曲线在告警设计上的用法 —— 你不是在调参数,你是在一条曲线上选工作点。
📐 三种阈值形式的对比
| 形式 | 优点 | 致命弱点 | 什么时候用 |
|---|---|---|---|
绝对阈值(< 3%) |
简单、好解释 | 被日内/周内周期打败 💀 | 只在没有周期性的指标上 |
| 环比(比 1 小时前) | 对突变敏感 | 对渐变完全失明 ⭐ | 抓管道故障 |
| 同比(比上周同时段)⭐ | 自动去周期 | 上周本身异常时会失效 | 业务指标的默认选择 |
| 和固定基线比(训练集/上线时) | 能抓慢漂移 ⭐ | 基线过期后全是噪声 | 特征分布、模型输出 |
💡 实践中的组合:业务指标用同比 + 固定基线两条线。 同比抓突变,固定基线抓慢漂移 —— 单独任何一条都会漏掉一整类问题。
⚠️ 告警设计的八个坑:
| 坑 | 后果 | 怎么修 |
|---|---|---|
| 一次故障报几十条 | 消息刷屏,真信息被淹 | 按根因收敛 + 合并连续告警 ⭐ |
| 告警只有指标名没有上下文 | 收件人无法判断,转手问人 | 带幅度、持续时间、负责人、手册链接 |
| 没有恢复通知 | 不知道问题好没好,一直挂着 | 恢复时也发一条 ⭐ |
| P0 太多 | 准确率崩,全员脱敏 💀 | 回测:P0 一个月 ≤ 1 次 |
| 规则上线后没人再看 | 阈值随业务增长早已失效 | 每季度重跑一次回测 ⭐ |
| 只在工作时间有值班 | 夜间事故第二天才发现 | 明确"夜间只保 P0"并说明后果 |
| 告警发到一个大群 | 责任分散,人人以为别人在看 | 指定到人,不是到群 ⭐⭐ |
| 没有升级路径 | 值班的人搞不定就卡住了 | 15 分钟未确认自动升级到 TL |
📓 九、一份可以照抄的值班手册模板
【告警名】特征 user_7d_click_cnt 均值漂移
【级别】 P1
【含义】 用户侧最重要的行为特征,均值偏离训练基线 3σ 以上并持续 30 分钟
① 30 秒判断
看这三个数:降级触发率 / 上游表 dw_user_action 新鲜度 / 预测值标准差
· 降级率 > 5% → 是特征服务问题,跳到 ③
· 上游表滞后 > 6 小时 → 是数据问题,跳到 ④
· 两者都正常 → 可能是真实漂移,跳到 ⑤
② 先止血
如果核心业务指标已经掉了 > 5%,先回滚,再继续查 ⭐
③ 特征服务问题
看服务日志 / 扩容 / 联系 @xxx(值班表见链接)
④ 上游数据问题
看调度平台任务状态 → 重跑 → 通知数据团队 @yyy
⚠️ 重跑期间【不要触发模型重训】(第 1 章:管道坏了时重训是有害的)
⑤ 真实漂移
跑一次对抗验证(第 6 章),看是哪些特征在漂
不紧急,转 P2 进日报,本周内分析
【升级】15 分钟未确认 → 自动 @ 组长
【相关看板】<链接> 【历史事故】<链接>
⭐ 模板里最关键的是 ①:它把"这个告警意味着什么"变成了三个可以立刻看的数。 没有这一步,值班的人会从"打开看板"开始 —— 而那通常要 10 分钟。 🔗 第 11 章会把这套判断扩展成一棵完整的排查树。
🔗 十、和站内其他章的关系
| 相关的地方 | 和这一章的关系 |
|---|---|
| 第 5 章定阈值要回测 | 这一章展开了怎么回测 |
| 第 7 章信号时间轴 | 早期信号该设成 P2 而不是 P0 |
| ML基础 05准确率-召回率 | 告警设计就是在选工作点 |
| 智能体工程 12 | Agent 的终止与告警设计同理 |
✅ 检查点
- 为什么说「每天响 20 次的告警比没有告警更糟」?关键的误报率数字是多少?
- 告警四个级别的划分依据是什么?P0 的判据是什么?
- 为什么绝大多数模型告警应该是 P2?
- 六个降低误报的技巧里,哪个性价比最高?为什么?
- 分人群看是为了防什么?
- 好的告警应该让人在多久内做出判断?要带哪些上下文?
- 告警回测时,只看误报率会有什么问题?
- 衡量监控体系最好的单一指标是什么?为什么不是「告警数量」?
- 「第 48 次」那个事故里,告警准确率是多少?为什么说责任不在值班同学身上?他们复盘后做了哪三件事?
- 告警系统该看哪四个数字?一次事故的实际影响时长由哪三段组成?哪一段最常被忽略?
- 回测那张表里,三条规则的召回都是 3/3,这说明了什么?该选哪条?
- 绝对阈值 / 环比 / 同比 / 固定基线各自的弱点是什么?业务指标推荐怎么组合?
- 为什么告警要「指定到人」而不是发到大群?
- 值班手册里最关键的是哪一部分?为什么?
👀 答案
- 因为它让你以为自己有监控,实际上没人看。关键数字:误报率超过 50% 就在心理上失效了——人不会持续响应"多半是假的"信号,这是必然不是态度问题。
- 按处理紧迫度。P0 判据:多等 1 小时会造成不可逆损失。
- 因为模型退化几乎总是渐进的,不需要半夜叫人。把 P2 的东西设成 P0 是告警疲劳的头号来源。
- 用同比而不是绝对值。因为业务指标几乎都有强周期性(日内、周内),用绝对阈值一定会被周期打败(如"订单<1000"凌晨 3 点必然触发)。
- 防辛普森效应:总体 CTR 没变,可能是新用户大跌 + 老用户小涨正好抵消。
- 30 秒内判断出要不要现在处理。要带:特征的业务名和变化幅度、持续时间、该特征的重要性排名、可能的上游线索、负责人、排查手册链接。
- 会把阈值调得过松,什么都报不出来。必须同时看漏报——拿历史上真实发生过的事故当测试集,确认规则能报出来。
- 发现延迟(从问题发生到被发现用了多久)。比"有多少个告警"有意义得多,后者只说明你加了多少规则。
- 1/48 = 2.1%。责任不在人身上,是因为在 2.1% 准确率下"先静音"是理性行为——一个人不可能每次都为 2% 的概率立刻起身,是告警设计逼出了这个行为。三件事:①规则从 P0 降到 P1 并加"连续 10 分钟"的持续条件 ②阈值改成和上周同一时段比 ③新增一条真正的 P0(降级触发率 > 20%,回测两个月只响 1 次)。结果 P0 从每月 24 次降到 0.5 次,而真事故仍能报出来。
- 准确率、召回率、MTTA、MTTR。实际影响时长 = 发现延迟 + MTTA + MTTR。MTTA 最常被忽略——很多团队只优化监控和回滚,而中间这段取决于人信不信你的告警,常常是最大的一块。
- 说明前两条多出来的 37 次和 4.5 次告警全部是纯噪声,一点额外的安全感都没换来。该选「同比 <上周70% 且持续 3 小时」(每月 1.5 次,召回 3/3,准确率 0.83)。核心方法:不要问"这个阈值合不合理",要问"在同样的召回下哪个规则误报最少"——你是在准确率-召回率曲线上选工作点。
- 绝对阈值被日内/周内周期打败;环比对渐变完全失明;同比在上周本身异常时失效;固定基线在基线过期后全是噪声。业务指标推荐 同比 + 固定基线两条线:同比抓突变、固定基线抓慢漂移,单独任何一条都会漏掉一整类问题。
- 因为发到大群会责任分散,人人以为别人在看。要指定到具体的人,并配 15 分钟未确认自动升级。
- ① 30 秒判断那一段——它把"这个告警意味着什么"变成三个可以立刻看的数(降级率 / 上游表新鲜度 / 预测标准差)并各自指向下一步。没有它,值班的人要从"打开看板"开始,那通常要 10 分钟。
🛑 可以停在这里
⚡ 走神救援
⭐每天响20次的告警比没有告警更糟——它让你以为自己有监控。关键数字:误报率>50% 在心理上就失效了(人不会持续响应多半是假的信号,这是必然不是态度问题)。四级:P0(判据是多等1小时会造成不可逆损失)/P1当天/P2进日报不推送/P3只记录;⭐绝大多数模型告警应该是P2(模型退化几乎总是渐进的),把P2设成P0是告警疲劳的头号来源。六个降误报技巧:①持续时间条件(连续30分钟)②⭐⭐用同比不用绝对值(性价比最高——业务指标都有强周期,绝对阈值一定被周期打败,"订单<1000"凌晨必然触发)③用分位数不用均值 ④分人群看防辛普森(总体没变可能是新用户大跌+老用户小涨抵消)⑤告警带上下文,让人30秒内判断要不要现在处理 ⑥按根因收敛(上游一张表挂了别报20条)。⭐上线前必须回测:跑60天历史数一数会报多少次;只看误报率会把阈值调太松,必须同时拿历史真实事故当测试集看漏报——告警系统本身就是个分类器,你在选工作点。⭐衡量监控体系最好的单一指标是「发现延迟」,不是告警数量。💀「第48次」:某风控团队两个月响了 48 次 P0,只有 1 次是真的(准确率 2.1%);真出事那次值班同学看一眼手机「又是这个」→ 静音,22 分钟后被客服 @ 醒 —— ⭐责任不在人身上,2.1% 下"先静音"是理性行为,是告警设计逼出来的。修法:降级到 P1 + 加持续条件 + 改同比 + 新增一条真 P0(降级率>20%),P0 从每月 24 次降到 0.5 次而真事故仍能报出。📊四个数字:准确率(P0 应 >50%)、召回率、MTTA、MTTR;⭐实际影响时长 = 发现延迟 + MTTA + MTTR,而 MTTA 最常被忽略——它取决于人信不信你的告警。⭐立刻可做:给每条告警加 👍/👎,两周后把准确率 <30% 的规则全删掉 —— 删一条噪声告警比加一条监控更能提升可靠性。🧪回测框架(合并连续告警成"事件"、算每月次数/召回/准确率):真实例子里三条规则召回都是 3/3,说明多出来的告警全是纯噪声;⭐⭐别问"阈值合不合理",问"同样召回下哪个规则误报最少"。四种阈值形式:绝对值被周期打败、环比对渐变失明、同比是业务指标默认、固定基线抓慢漂移 → 同比+固定基线两条一起用。八坑里最狠的:P0 太多、告警发到大群而不是指定到人、规则上线后再没回测过。值班手册的关键是"30秒判断"那三个数。
下一节 👉 09-特征重要性的三种谎言.md ⭐