SLO 与燃烧率告警 · 从根上解决阈值问题

错误预算把「可靠性」变成一种可以花的预算。这一章讲清 SLI/SLO/错误预算三件套、燃烧率(burn rate)的定义与那张经典的多窗口告警表,以及为什么它同时解决了误报、漏报和低流量三个难题——附可直接抄的规则。

作者 David更新于 第 34 篇(共 52 篇)

SLO 与燃烧率告警 · 从根上解决阈值问题

上一章讲了四种定阈值的方法,但都有点将就。有没有一种方法能从根上解决?

有。它来自 Google SRE,叫基于错误预算燃烧率的告警。这是现代告警工程的最佳实践,也是本部分最有价值的一章。

三件套:SLI / SLO / 错误预算

先把三个词分清——它们经常被混用,但含义完全不同:

词是什么例子
SLI(指标)你测的那个数成功请求数 / 总请求数
SLO(目标)你给自己定的目标SLI ≥ 99.9%(按 30 天滚动窗口)
错误预算1 − SLO,你被允许失败的额度0.1% = 30 天里约 43 分钟
SLA(协议)对外的合同,违约要赔钱通常比 SLO 宽松

SLI 是事实,SLO 是目标,错误预算 是两者之差。 注意 SLO 必须带时间窗口(“30 天内 99.9%”),否则无意义。

关键思维转变:预算是用来花的

错误预算最反直觉、也最有价值的一点:它不是“底线”,而是“额度”——你应该把它花掉。**

传统思维:“任何故障都是失败,我们要追求零故障。” 错误预算思维:“我们被允许在 30 天内故障 43 分钟。没用完的预算是浪费的。”

为什么“没用完是浪费”?因为可靠性是有成本的,而且成本随着九的增加指数上升:

  • 如果你长期只用掉 10% 的预算,说明你过度投资了可靠性——那些工程时间本可以拿去做新功能。
  • 预算充足时,应该更激进:更快地发布、多做实验、多搞混沌工程。
  • 预算快烧完时,才该踩刹车:冻结发布、专心修稳定性。

这把“要不要发布”这个永恒的争吵,从“拍脑袋 / 谁嗓门大”变成了一个数据驱动的决策**:**

错误预算还剩 60% → 发!
错误预算还剩 5%  → 冻结,先修

这是 SRE 最重要的文化贡献:它让“稳定性”和“速度”从对立变成了一个可量化的权衡。 而且它给了开发和运维同一个数字去争论,而不是各说各话。

燃烧率:预算烧得多快

燃烧率(burn rate)= 当前错误率 / 错误预算率。它的物理意义是“按这个速度,预算会被用完得多快”。

SLO = 99.9%  →  错误预算率 = 0.1%

当前错误率 0.1%  →  燃烧率 = 1    → 30 天正好烧完(符合预期)
当前错误率 1%    →  燃烧率 = 10   → 3 天就烧完(!)
当前错误率 10%   →  燃烧率 = 100  → 7.2 小时烧完(!!)
当前错误率 0.01% →  燃烧率 = 0.1  → 300 天才烧完(过度可靠)

燃烧率 = 1 意味着“刚好按计划消耗”。> 1 就是在超支。

这个定义的美妙之处:它把“错误率多少算严重”这个问题,变成了“预算多久会烧完”——而后者有明确的、可行动的含义。 燃烧率 14.4 意味着“2 天的预算会在 1 小时内烧光”,这显然该叫醒人;燃烧率 1.5 意味着“会略微超支”,开个工单就行。

阈值不再需要拍脑袋——它由“你愿意在多久内烧掉多少预算”推导出来。

多窗口多燃烧率:那张经典的表

《SRE Workbook》给出的方案(业界事实标准):用几组不同的窗口 + 燃烧率,兼顾“快速发现严重问题”和“不漏掉慢性问题”。

严重度燃烧率长窗口短窗口含义动作
紧急14.41h5m2 天预算会在 1 小时内烧光page
紧急66h30m2 天预算在 6 小时内烧光page
一般31d2h10% 预算 1 天内烧掉ticket
一般13d6h慢性劣化ticket

为什么要“长窗口 + 短窗口”两个条件同时满足?

  • 长窗口 —— 判断“问题足够严重/持久”。它防误报:一次抖动不会让 1 小时的燃烧率飙到 14.4。
  • 短窗口 —— 判断“问题还在持续”。它让告警快速恢复:问题解决后,5 分钟窗口立刻降下来,告警就消了;如果只看 1 小时窗口,问题修好后告警还要挂 1 小时。

两个窗口是一对:长的防误报,短的保证快速恢复。 这比 for 子句更精细——for 只能延迟触发,而短窗口能加速恢复。

为什么燃烧率越高、窗口越短? 因为严重程度和紧迫性成正比:烧得越快,越该早发现(1 小时窗口);烧得慢的(燃烧率 1),你有几天时间反应,可以用 3 天窗口慢慢确认——这样既不会漏掉“慢性失血”,也不会为它半夜叫人。

可以直接抄的规则

配合上一章的 recording rules(多窗口错误率已预聚合好):

groups:
- name: slo-alerts
  rules:
  # 紧急:14.4 倍燃烧率(1h 且 5m 都超标)
  - alert: ErrorBudgetBurnFast
    expr: |
      (
        service:http_errors:ratio_rate1h > (14.4 * 0.001)
        and
        service:http_errors:ratio_rate5m > (14.4 * 0.001)
      )
    labels:
      severity: page
    annotations:
      summary: "{{ $labels.service }} 正在快速烧错误预算(2 天的预算 1 小时内烧光)"
      runbook_url: "https://wiki/runbooks/error-budget-burn"

  # 紧急:6 倍燃烧率(6h 且 30m)
  - alert: ErrorBudgetBurnMedium
    expr: |
      (
        service:http_errors:ratio_rate6h > (6 * 0.001)
        and
        service:http_errors:ratio_rate30m > (6 * 0.001)
      )
    labels:
      severity: page

  # 一般:3 倍燃烧率(1d 且 2h)→ 工单
  - alert: ErrorBudgetBurnSlow
    expr: |
      (
        service:http_errors:ratio_rate1d > (3 * 0.001)
        and
        service:http_errors:ratio_rate2h > (3 * 0.001)
      )
    labels:
      severity: ticket

注意 0.001 就是错误预算率(1 − 99.9%)。改 SLO 只需要改这个数。

注意这里不需要 for —— 长窗口本身已经起到了防抖作用(1 小时的平均错误率不会因为一次抖动就飙升)。这是燃烧率方案的又一个优点:少一个要调的参数。

它同时解决了三个难题

回头看,燃烧率方案一口气解决了前面几章提到的所有痛点:

一套机制解决六个问题,这就是为什么它是现代告警的最佳实践。

落地建议

① 别一上来就给所有服务定 SLO

从最关键的 1~2 个用户旅程开始(比如“下单”、“登录”)。SLO 应该覆盖“用户旅程”,不是“每个微服务”——用户不在乎你的 auth 服务可用性,他在乎“能不能登录成功”。

② SLO 要和业务方达成一致

99.9% 还是 99.95%,这是个商业决策(多一个九要多花多少钱?值吗?)。技术团队单方面定的 SLO 没有意义——因为“预算烧完要冻结发布”这个约束,必须是业务方也认的。

③ 先观察再执行

新定的 SLO 先只看不告警,跑几周,看真实的燃烧率长什么样。如果基线就达不到 SLO,那不是告警问题,是系统或 SLO 本身的问题。

④ 别忘了延迟 SLO

成功率只是一半。“99.9% 的请求在 300ms 内成功”才是完整的 SLI——慢和坏在用户眼里没区别。延迟 SLI 通常表达为“快于阈值的请求占比”:

# 延迟 SLI:P99 < 300ms 等价于"99% 的请求 < 300ms"
sum(rate(http_request_duration_seconds_bucket{le="0.3", status=~"2.."}[5m]))
/ sum(rate(http_request_duration_seconds_count{status=~"2.."}[5m]))

注意这里直接用了 le="0.3" 这个桶——所以桶边界必须正好在 SLO 阈值上!这是第 2 部分那条“桶要在 SLO 阈值附近加密”的硬核理由:没有 le="0.3" 这个桶,你根本算不出这个 SLI。

小结与下一章

SLI(事实)/ SLO(目标,必带时间窗口)/ 错误预算(1−SLO)。关键思维转变:预算是用来花的,不是底线——没用完说明过度投资了可靠性,那些工程时间本可做新功能;预算充足就激进发布,快烧完才踩刹车。这让“稳定性 vs 速度”从争吵变成数据驱动的决策。燃烧率 = 当前错误率 / 错误预算率,物理意义是“预算多久烧完”——阈值由此推导,不用拍脑袋。多窗口多燃烧率(14.4/1h+5m → page;6/6h+30m → page;3/1d+2h → ticket):长窗口防误报、短窗口保证快速恢复,两者是一对;燃烧率越高窗口越短(严重度 ∝ 紧迫性)。它一口气解决六个问题:阈值有依据、误报少(长窗口自带防抖,不用 for)、不漏慢性失血、低流量陷阱自动消失、严重度自然分级、天然对症状告警。落地:从关键用户旅程而非每个微服务开始、SLO 要业务方认可、先观察再执行、别忘延迟 SLO——延迟 SLI 直接用 le="0.3" 桶,这是“桶必须落在 SLO 阈值上”的硬核理由。

告警规则写好了,但通知怎么送到人?下一章看 Alertmanager。👉 Alertmanager。

参考资料

本页目录