SLO 与错误预算 把稳定性变成可交易的额度
"我们要做到 99.9%"——这句话没有任何操作性,因为没人回答谁在消耗这个承诺、谁负责、超了怎么办。错误预算的价值在于,它把稳定性从模糊口号变成一份可以花钱的预算:有余量就多发布功能,超支就冻结变更去修可靠性。
一、SLO 必须由 SLI 支撑
三层关系要分清:SLO 是承诺,SLI 是测量方式,错误预算是 SLO 允许失败的量。
SLO: 订单查询接口月度可用性不低于 99.5%
SLI: 好请求数 ÷ 总请求数,其中"好"等于状态码低于 500 且延迟低于 500ms
预算: 30 天 × 0.5%,即约 216 分钟不可用,或等价的坏请求配额
四个实践要求:
- SLI 必须站在用户视角测量。服务自己日志里统计的成功率不算,要从入口(网关或前端)测;
- 延迟 SLI 用比例阈值型("95% 的请求快于 300ms"),不要用平均延迟;
- SLO 数量要少,3 到 7 个覆盖核心用户旅程即可,给每个接口都配 SLO 等于没有 SLO;
- 承诺对象是用户而不是上级。写进 SLO 的数字必须能够公开解释。
service: order-api
objectives:
- name: availability
sli: good_requests / total_requests
target: 99.5
window: 30d
burn_rate_alerts:
- { short: 5m, long: 1h, budget_burn: 14.4 } # page
- { short: 30m, long: 6h, budget_burn: 6 } # page
- { short: 6h, long: 3d, budget_burn: 1 } # ticket
- name: latency
sli: "latency below 500ms"
target: 95
window: 30d
二、多窗口多速率告警
单窗口告警要么太吵要么太迟钝。正确形态是短窗口确认加长期窗防抖,判据是"预算燃烧速率"。
sum(rate(requests_total{code=~"5.."}[5m])) / sum(rate(requests_total[5m]))
/ (1 - 0.995) > 14.4
为什么是 14.4:30 天窗口下允许 0.5% 失败,若以 14.4 倍速率燃烧,约 2 天就会耗尽整个月预算。
组合规则要同时满足才 page:
5m 窗口 burn > 14.4 AND 1h 窗口 burn > 14.4 # 快速大规模故障
30m 窗口 burn > 6 AND 6h 窗口 burn > 6 # 中速持续消耗
6h 窗口 burn > 1 AND 3d 窗口 burn > 1 # 慢性漏,转工单
这套机制的价值在于:既能在几分钟内叫醒人(短窗口),又不会因为一次抖动就 page(长窗口 AND),还能在预算被慢性耗尽时提前预警,而不是月底才发现预算已经花光。
三、预算视图要足够直白
预算必须有一个所有人都能看到的单一视图,否则不会改变任何行为。
type Budget struct {
Objective string
Window time.Duration
Target float64 // 0.995
Consumed float64 // 窗口内已消耗的坏请求比例
Remaining float64 // 剩余预算百分比
DepletionAt time.Time // 按当前速率预计耗尽时间
}
func (b *Budget) BurnRate(elapsed time.Duration) float64 {
expected := b.Consumed / (elapsed.Seconds() / b.Window.Seconds())
allowed := 1 - b.Target
return expected / allowed
}
看板上最有效的三个数字是:剩余预算百分比(大字号)、预计耗尽时间、当前燃烧速率。它们比任何时序图都更能影响决策。
四、政策:预算花完会发生什么
没有后果的 SLO 是装饰品。政策要事前写死、事后严格执行。一份可抄的最小政策:
剩余 > 50% 正常发布节奏,允许高风险变更
剩余 20~50% 高风险变更需 SRE 会签
剩余 0~20% 仅允许修复类与安全类变更,功能发布暂停
剩余 < 0 特性冻结,本迭代全部投入可靠性工作
恢复条件:连续 7 天滚动 burn_rate 低于 1
三条执行要点:冻结必须真的执行,第一次超支不冻结,这项制度从此作废;冻结要有明确出口(比如连续 7 天 burn 低于 1),否则会变成无限期惩罚,团队的第一反应就是把 SLO 数字改松;例外走一次性授权,业务必须发布时由负责人书面承担风险并记录,事后回顾。
五、归因:把预算变成排期工具
只报"还剩多少预算"不够,要回答"预算花在哪了",这决定下个迭代做什么。
预算消耗归因(30 天)
依赖超时(下游 payment-svc 抖动) 38%
发布相关(3 次发布造成的抖动) 24%
容量不足(峰值 CPU 打满) 18%
未捕获 panic 12%
其他 8%
有了这张表,排期决策变得简单:优先做支付超时兜底,而不是继续扩容。数据来源是把每次故障的预算消耗分钟数记进事故记录并打标签,季度汇总。
六、五个常见反模式
- 给内部依赖定 SLO 而不管用户旅程。数据库 99.99% 但用户下单成功率只有 92%,这是一套失败的 SLO 体系;
- 数字定得太高。一开始写 99.99% 的团队,三个月后要么改数字要么放弃机制,宁可从 99% 起步稳定后再收紧;
- 与个人绩效挂钩。结果一定是把 SLI 测量方式改松(放宽超时阈值、缩小 5xx 判定范围);
- 只测服务端不测前端。用户感知的失败中,CDN、DNS、浏览器与弱网占比常被严重低估;
- 窗口太短。7 天窗口的 SLO 波动过大,会造成频繁冻结与解冻,团队无法工作。30 天是常见选择,成熟后再看 90 天趋势。
正确的收紧节奏是:季度回顾时看上季度 burn 分布,若长期低于 0.3,下个季度提一档。SLO 是长期承诺,不是当期考核指标。
小结
错误预算制度要跑起来需要五块拼齐:用户视角的 SLI、少而关键的目标、多窗口多速率告警、事前写死且有出口的政策、预算消耗归因。前三者是技术工作,后两者是组织约定,真正的难点在这里——政策必须被执行一次,机制才有信用。落地建议从一个核心用户旅程起步,跑两个完整预算周期,把冻结与归因各执行一次,机制立住之后再扩展到其他目标。
评论(0)
登录 后参与评论。