🏠 总目录📚 本教程 08 · 告警为什么没人看 ← →
📑 本页目录(点开跳转)

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 条告警 💀
⭐ 按【根因】聚合:同一时间窗内、同一上游来源的告警合并成一条

🧪 四、告警上线前必须做的一件事:回测

操作步骤

  1. 拿过去 60 天的历史数据
  2. 用你打算设的规则跑一遍
  3. 数一数:会报多少次警?
  4. 判断标准(经验值):
  5. · P0:一个月 ≤ 1 次 —— 多了就不是 P0
  6. · P1:一周 ≤ 2 次
  7. · P2:一天 ≤ 几次都可以(反正不推送)
  8. 再看:那几次已知的真实事故,这个规则能报出来吗?⭐

⭐ 第 ④ 步是关键:只看误报率会让你把阈值调得过松,什么都报不出来。 必须同时看漏报:拿历史上真实发生过的事故当测试集。

💡 这其实就是准确率-召回率权衡在告警设计上的应用 (🔗 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.53 / 30.08天天响
同比 < 上周 70%6.03 / 30.42还是太多
同比 < 上周 70%,且持续 3 小时1.53 / 30.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 的终止与告警设计同理

✅ 检查点

  1. 为什么说「每天响 20 次的告警比没有告警更糟」?关键的误报率数字是多少?
  2. 告警四个级别的划分依据是什么?P0 的判据是什么?
  3. 为什么绝大多数模型告警应该是 P2?
  4. 六个降低误报的技巧里,哪个性价比最高?为什么?
  5. 分人群看是为了防什么?
  6. 好的告警应该让人在多久内做出判断?要带哪些上下文?
  7. 告警回测时,只看误报率会有什么问题?
  8. 衡量监控体系最好的单一指标是什么?为什么不是「告警数量」?
  9. 「第 48 次」那个事故里,告警准确率是多少?为什么说责任不在值班同学身上?他们复盘后做了哪三件事?
  10. 告警系统该看哪四个数字?一次事故的实际影响时长由哪三段组成?哪一段最常被忽略?
  11. 回测那张表里,三条规则的召回都是 3/3,这说明了什么?该选哪条?
  12. 绝对阈值 / 环比 / 同比 / 固定基线各自的弱点是什么?业务指标推荐怎么组合?
  13. 为什么告警要「指定到人」而不是发到大群?
  14. 值班手册里最关键的是哪一部分?为什么?
👀 答案
  1. 因为它让你以为自己有监控,实际上没人看。关键数字:误报率超过 50% 就在心理上失效了——人不会持续响应"多半是假的"信号,这是必然不是态度问题。
  2. 按处理紧迫度。P0 判据:多等 1 小时会造成不可逆损失。
  3. 因为模型退化几乎总是渐进的,不需要半夜叫人。把 P2 的东西设成 P0 是告警疲劳的头号来源。
  4. 用同比而不是绝对值。因为业务指标几乎都有强周期性(日内、周内),用绝对阈值一定会被周期打败(如"订单<1000"凌晨 3 点必然触发)。
  5. 防辛普森效应:总体 CTR 没变,可能是新用户大跌 + 老用户小涨正好抵消。
  6. 30 秒内判断出要不要现在处理。要带:特征的业务名和变化幅度、持续时间、该特征的重要性排名、可能的上游线索、负责人、排查手册链接。
  7. 会把阈值调得过松,什么都报不出来。必须同时看漏报——拿历史上真实发生过的事故当测试集,确认规则能报出来。
  8. 发现延迟(从问题发生到被发现用了多久)。比"有多少个告警"有意义得多,后者只说明你加了多少规则。
  9. 1/48 = 2.1%。责任不在人身上,是因为在 2.1% 准确率下"先静音"是理性行为——一个人不可能每次都为 2% 的概率立刻起身,是告警设计逼出了这个行为。三件事:①规则从 P0 降到 P1 并加"连续 10 分钟"的持续条件 ②阈值改成和上周同一时段比 ③新增一条真正的 P0(降级触发率 > 20%,回测两个月只响 1 次)。结果 P0 从每月 24 次降到 0.5 次,而真事故仍能报出来。
  10. 准确率、召回率、MTTA、MTTR。实际影响时长 = 发现延迟 + MTTA + MTTR。MTTA 最常被忽略——很多团队只优化监控和回滚,而中间这段取决于人信不信你的告警,常常是最大的一块。
  11. 说明前两条多出来的 37 次和 4.5 次告警全部是纯噪声,一点额外的安全感都没换来。该选「同比 <上周70% 且持续 3 小时」(每月 1.5 次,召回 3/3,准确率 0.83)。核心方法:不要问"这个阈值合不合理",要问"在同样的召回下哪个规则误报最少"——你是在准确率-召回率曲线上选工作点。
  12. 绝对阈值被日内/周内周期打败;环比对渐变完全失明;同比在上周本身异常时失效;固定基线在基线过期后全是噪声。业务指标推荐 同比 + 固定基线两条线:同比抓突变、固定基线抓慢漂移,单独任何一条都会漏掉一整类问题。
  13. 因为发到大群会责任分散,人人以为别人在看。要指定到具体的人,并配 15 分钟未确认自动升级。
  14. ① 30 秒判断那一段——它把"这个告警意味着什么"变成三个可以立刻看的数(降级率 / 上游表新鲜度 / 预测标准差)并各自指向下一步。没有它,值班的人要从"打开看板"开始,那通常要 10 分钟。

🛑 可以停在这里

⚡ 走神救援

⭐ 每天响 20 次的告警比没有告警更糟——它让你以为自己有监控。 误报率超过一半之后,人就不会再持续响应了;这是必然,不是态度问题。

四级里绝大多数模型告警应该是 P2(模型退化几乎总是渐进的)。把 P2 当 P0 是告警疲劳的头号来源。P0 的判据只有一条:多等一小时会造成不可逆损失。

降误报最值钱的两招:用同比不用绝对值(业务指标都有周期,绝对阈值必然被凌晨打败)和加持续时间条件。其余四招:分位数代替均值、分人群看、告警带上下文、按根因收敛。

⭐ 上线前必须拿历史回测,而且不能只看误报——要拿历史真实事故当测试集看漏报。 告警系统本身就是个分类器,你是在选工作点。

💀 那个「第 48 次」:两个月响了 48 次 P0 只有 1 次是真的,真出事时值班同学静音了,22 分钟后被客服叫醒。责任不在人身上——那个准确率下先静音是理性行为,是告警设计逼出来的。

⭐ 立刻能做的一件事:给每条告警加 👍/👎,两周后删掉准确率最低的那批规则。删一条噪声告警比加一条监控更能提升可靠性。

下一节 👉 09-特征重要性的三种谎言.md ⭐

打卡记录保存在你的浏览器里,首页能看到总进度