bigywater.tech
微服务 · 74

SLO 与错误预算的计算

错误预算怎么算?一次 6 秒的事故消耗多少预算?燃烧速率告警怎么设窗口和阈值?快燃烧和慢燃烧各能发现什么、迟多久?这篇用 Prometheus 3.15.0 和已知错误数的模拟流量逐项算出来。

43.2 分钟
99.9% 的 SLO 在 30 天里允许的完全不可用时间(99.99% 是 4.3 分钟)
61%
300 s 预算窗口的模拟里,一次 6 s、30% 失败的事故消耗的预算
104%
3% 的持续错误(燃烧速率 3)被慢燃烧条件发现时,预算已经消耗的比例

预算的算术

实测 · 本机执行输出
  SLO     | 30 天允许的完全不可用时间 | 秒       | 错误预算(允许的错误比例)
  --------+----------------+---------+--------------
  99%     | 432.0 分钟       | 25920 秒 | 0.01000      
  99.9%   | 43.2 分钟        | 2592 秒  | 0.00100      
  99.99%  | 4.3 分钟         | 259 秒   | 0.00010      
  99.999% | 0.4 分钟         | 26 秒    | 0.00001      
  每增加一个 9,预算缩小为原来的十分之一;错误预算是“允许失败的请求比例”,不是时间:没有全部挂掉、只是一部分请求失败时,按失败的请求占比消耗预算
  30 天窗口下常见的多窗口燃烧速率告警取值(长窗口 / 短窗口,燃烧速率阈值),以及按“燃烧速率 × 窗口 ÷ 30 天”算出来的、触发时已经消耗的预算比例(算出来的):
  窗口(长 / 短)    | 燃烧速率阈值 | 触发时已消耗的 30 天预算比例
  -------------+--------+-----------------
  1 小时 / 5 分钟  | 14.4×  | 2%              
  6 小时 / 30 分钟 | 6×     | 5%              
  3 天 / 6 小时   | 1×     | 10%             

每多一个 9,预算缩小为 1/10;预算是允许失败的请求比例。

剩余预算

实测 · 本机执行输出
  时刻      | 累计错误(程序计数) | 已消耗的预算 | 剩余预算 | Prometheus increase 算出的累计错误
  --------+------------+--------+------+----------------------------
  第 29 秒  | 5          | 1%     | +99% | 5                          
  第 37 秒  | 366        | 61%    | +39% | 372                        
  第 99 秒  | 378        | 63%    | +37% | 380                        
  第 130 秒 | 558        | 93%    | +7%  | 560                        
  第 161 秒 | 738        | 123%   | -23% | 740                        
  第 299 秒 | 766        | 128%   | -28% | 767                        
  预算按“失败的请求数”消耗:事故 A 只有 6 s、但 30% 的请求失败;事故 B 错误率只有 3%、但持续 60 s;两者各消耗了预算的相当一部分,再加上基线的 0.1%,到窗口结束时预算已经用完。两者换成时间的话,A 相当于 6 × 0.3 = 1.8 s 的完全不可用(算出来的)

预算按失败的请求数消耗,短而严重的事故和长而轻微的事故可以消耗同样多的预算。

燃烧速率告警

实测 · 本机执行输出
  告警条件                             | 事故 A(30% 失败,6 s)                                | 事故 B(3% 失败,60 s)                                    | 事故之外的触发点数
  ---------------------------------+-------------------------------------------------+-----------------------------------------------------+----------
  (a)快燃烧:燃烧速率(12 s)> 10 且(2 s)> 10 | 第 34 秒起(开始后 +4 s,此时已消耗预算 61%),第 36 秒止(结束后 +0 s) | 没有触发                                                | 0        
  (b)慢燃烧:燃烧速率(60 s)> 2 且(6 s)> 2   | 第 32 秒起(开始后 +2 s,此时已消耗预算 41%),第 40 秒止(结束后 +4 s) | 第 139 秒起(开始后 +39 s,此时已消耗预算 104%),第 161 秒止(结束后 +1 s) | 0        
  (c)朴素:10 s 错误率 > 5%              | 第 32 秒起(开始后 +2 s,此时已消耗预算 41%),第 43 秒止(结束后 +7 s) | 没有触发                                                | 0        
  事故 A 的燃烧速率是 30,B 是 3:快燃烧(阈值 10)只看得到 A,慢燃烧(阈值 2)两个都看得到但要等长窗口里累积到阈值——B 的发现比 A 晚得多;朴素的“10 s 错误率 > 5%”看不到 3% 的持续错误。短窗口的作用是事故结束之后让告警尽快清除
ERRORS {}

快燃烧发现短而严重的事故,慢燃烧发现长而轻微的事故;短窗口让告警在事故结束后很快清除;窗口和阈值要按预算窗口设计。

分步演示

SLO 与错误预算
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.8 / Go / nginx / Envoy / etcd / Consul / Nacos / OpenTelemetry / Prometheus(按各篇注明用到哪些及版本);所有服务都是本机自己起的进程,端口 9150 以上,只监听 127.0.0.1,不连任何外部服务,不碰本机已有的实例;故障用 kill -9 进程、让连接断开或在代码里注入延迟与错误来制造;计时用 time.perf_counter,数字每次运行会有小幅抖动。Prometheus 3.15.0;“流量”是我程序按设定的错误率生成的 counter(每秒 200 个请求,没有真实的 HTTP 调用),累计错误数是程序自己的计数,与 Prometheus 的 increase 相差 1~6 个;预算窗口只有 300 s,告警窗口和阈值是为这个小窗口选的,不是 30 天窗口下的取值(第一节的 30 天取值只是算术);每个情形只跑了一次
    • 没有验证:30 天窗口下多窗口燃烧速率告警的实际行为;按延迟的 SLO(请求比例超过阈值就算“坏”)与可用性 SLO 的区别;Sloth / Pyrra 等工具生成的规则;预算耗尽之后的策略(冻结发布);SLO 的窗口是滚动还是日历月;流量很低时预算的统计误差
    京ICP备2026067502号-1京公网安备11010502063487号