背景
我做了 10 年 SRE,最近给一条核心交易链路(P99 SLO 300ms、30 天窗口,对外承诺 99.95%)上了 Google SRE Book 那套「多窗口多 burn rate」告警:
- 快窗口:1h / 2h,burn rate 14.4x(P1 page)
- 慢窗口:6h / 3d,burn rate 6x(P2 page)
- 兜底:3d / 30d,burn rate 1x(ticket)
上线 3 周,page 月均 40 次左右,我复盘逐条看,至少 30+ 次是误报(同一时段 2 个窗口互相触发、低流量时段瞬时尖峰、上游抖动 2-3 分钟自愈……)。值班同学已经开始「看 ID 不看内容」,这比没有告警更糟。
现象
- 误报集中在低流量时段:凌晨 3-5 点 QPS 跌到 200 左右,1h 窗口里只要出现 30-40 个错误(可能是 1 个上游 pod 抖动 2 分钟就够),burn rate 瞬间破 14.4x。
- 快慢窗口互相打架:慢窗口 6h/6x 在白天正常时段也频繁触发——因为 30 天预算被前面几次真故障烧掉 8%,剩余预算变薄,慢窗口阈值实际更敏感了。
- 真故障反而被淹没:有一次 25 分钟的真实 P0(DB 慢查询导致 P99 全链路劣化),我们是在 page 第 4 次才有人看的,前 3 次都被当成"又一次抖动"忽略了。
已尝试的排查与结果
- 给 burn rate 加"最小错误数"门槛(1h 窗口内至少 50 个错误才触发)——压掉了凌晨大部分误报,但白天某次真实故障的前 5 分钟错误数不到 50,漏了 5 分钟响应窗口。
- 把快窗口从 1h 拉长到 3h——误报降了,但 P0 响应从 5min 拖到 20min,业务侧不接受。
- 把 14.4x 调到 20x(拍脑袋)——误报少了,但漏报风险我算不清,没敢全量推。
- 加了"错误预算剩余 < 5% 才允许 page"的总闸——解决了"预算烧完还在 page"的尴尬,但没解决核心问题:单次告警的阈值本身该怎么定。
- 想给每个时段配不同阈值(白天 14.4x / 凌晨 25x)——规则复杂到维护不动,回退了。
期望得到的答案形态
- 阈值该从哪儿调:你们线上是"burn rate 数值"往上抬、"窗口长度"拉长、还是"加最小样本量"这三者里选一个为主?各自的取舍你怎么权衡?
- 有没有人做过"反推":从"月均 page ≤ 4 次"这个目标倒推 burn rate 该设多少?具体怎么算(给我公式 + 一个数字例子最好),还是只能靠 2 周灰度 + 误报/漏报双指标迭代?
- 低流量时段怎么单独处理:你们是用"最小错误数门槛"、"动态窗口(错误数没到 50 就继续累积)"、还是干脆凌晨降级到 ticket?
- 预算已消耗 8%+ 之后,告警阈值要不要联动收紧:Google 原文好像没明说,你们线上怎么处理"预算越花越敏感"这个副作用?
- 多窗口互相打架怎么解:你们 fast/slow 窗口是"任一触发就 page"还是"都触发才 page"?后者会不会漏掉短促故障?
坐标:Java 17 / Spring Boot 3.2 / K8s 1.28 / Prometheus + Alertmanager,核心链路 1000-5000 QPS(白天)/ 200-400 QPS(凌晨),P99 SLO 300ms / 99.95% 30 天窗口。
引用:站内文章 993《别再说 99.9% 了:错误预算怎么从 SLO 推导、怎么花、怎么和产品谈》讲得很清楚"预算怎么花",但"花的时候告警怎么设"这块我没看到展开,所以来问。