🏠 总目录📚 本教程 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 条告警  💀

   ⭐ 按【根因】聚合:同一时间窗内、同一上游来源的告警合并成一条

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

   ① 拿过去 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 的终止与告警设计同理

✅ 检查点

  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 + MTTRMTTA 最常被忽略——很多团队只优化监控和回滚,而中间这段取决于人信不信你的告警,常常是最大的一块。
  11. 说明前两条多出来的 37 次和 4.5 次告警全部是纯噪声,一点额外的安全感都没换来。该选「同比 <上周70% 且持续 3 小时」(每月 1.5 次,召回 3/3,准确率 0.83)。核心方法:不要问"这个阈值合不合理",要问"在同样的召回下哪个规则误报最少"——你是在准确率-召回率曲线上选工作点。
  12. 绝对阈值被日内/周内周期打败;环比对渐变完全失明;同比在上周本身异常时失效;固定基线在基线过期后全是噪声。业务指标推荐 同比 + 固定基线两条线:同比抓突变、固定基线抓慢漂移,单独任何一条都会漏掉一整类问题
  13. 因为发到大群会责任分散,人人以为别人在看。要指定到具体的人,并配 15 分钟未确认自动升级。
  14. ① 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

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