“99.9% 可用性"是句漂亮话——如果没有度量口径,99.9% 只是 PPT 上的数字。SLO(Service Level Objective)把"可靠性"变成可度量、可预算、可执行的工程对象:先用 SLI 定义"什么算好”,再用 SLO 设定"好到什么程度",错误预算则回答"今天能承受多少失败、什么时候该刹车"。本指南完整覆盖 SLO 与错误预算工程:SLI 设计(可用性/延迟/错误率)、SLO 目标与错误预算计算、Multi-window/Multi-burn-rate 告警、错误预算耗尽后的发布冻结、SRE 值班、与混沌工程/发布门禁的联动,以及 Prometheus/Pyrra 落地工具与真实案例。
目录
- 1. 为什么需要 SLO 与错误预算
- 2. SLI 设计:可用性 / 延迟 / 错误率
- 3. SLO 目标设定与错误预算计算
- 4. 告警策略:Multi-window / Multi-burn-rate
- 5. 错误预算耗尽:冻结发布与恢复
- 6. SRE 值班与 On-Call
- 7. 与混沌工程 / 发布门禁联动
- 8. 工具落地:Prometheus / Pyrra
- 9. 案例与最佳实践
1. 为什么需要 SLO 与错误预算
1.1 没有 SLO 的两种极端
极端一:拍脑袋定"五个九"(99.999%)
- 成本极高:冗余、压测、人工值守都按最高标准
- 团队不敢发布:任何风险都被拒绝
极端二:没有目标
- 可靠性靠运气:挂了再修,坏了再说
- 没有度量:无法判断"变好还是变坏"
SLO 的价值:把可靠性从"口号"变成"预算"
像管理钱一样管理可用性——有限预算,花在刀刃上
1.2 SLO / SLA / SLI 的关系
SLI(指标):实际测得的服务水平,如"请求成功率 99.95%"
SLO(目标):我们承诺的内部目标,如"月成功率 ≥ 99.9%"
SLA(对外契约):给客户的法律承诺,如"月可用性 ≥ 99.9%,否则退款"
关系:SLA 一定基于 SLO,SLO 一定基于 SLI
通常 SLO 比 SLA 更严格(给自己留缓冲)
💡 核心观点:SLO 的本质是"为可靠性设预算"——错误预算就是"允许失败的时间"。预算充足时可以放开发布,预算耗尽就必须停手修复。这把"快"和"稳"的矛盾转化为一个可计算的数字。
2. SLI 设计:可用性 / 延迟 / 错误率
2.1 好 SLI 的选取原则
SLI 要"对用户有意义":
- 从用户旅程出发,选用户真正感知的指标
- 请求成功率(可用性)是最常见 SLI
- 有时要细分:读路径 / 写路径 / 关键接口各自定义
原则:宁选"一个能准确反映用户体验的 SLI",不选"一堆无感的指标"
2.2 三类典型 SLI
| SLI 类型 | 定义 | 示例目标 |
|---|---|---|
| 可用性 | 成功请求 / 总请求 | 月成功率 ≥ 99.9% |
| 延迟 | 请求耗时 P 分位 | P95 延迟 ≤ 300ms |
| 错误率 | 错误请求 / 总请求 | 错误率 ≤ 0.1% |
2.3 SLI 量化示例(Prometheus)
# 可用性 SLI:5 分钟内成功请求占比
sum(rate(http_server_request_count{status!~"5..|4.."}[5m]))
/ sum(rate(http_server_request_count[5m]))
# 延迟 SLI:P95 延迟
histogram_quantile(0.95, sum(rate(http_server_request_duration_bucket[5m])) by (le))
2.4 定义窗口与口径
- 统计窗口:过去 28 天 / 30 天(滚动)
- 有效请求:排除爬虫、监控探针(防污染)
- 成功判定:HTTP 2xx/3xx,业务错误码要单独定义
- 测量位置:客户端(最能反映用户体验)优先,或入口网关
3. SLO 目标设定与错误预算计算
3.1 SLO 目标怎么定
三步设定法:
1. 看现状:当前真实 SLI 是多少(先度量再承诺)
2. 定目标:比现状略严一点,但可达(别一步登天五个九)
3. 留缓冲:SLO 严于 SLA(如 SLA 99.9%,SLO 设 99.95%)
3.2 错误预算计算
月错误预算 = 总时间 ×(1 - SLO)
SLO 99.9% → 每月允许失败 0.1% ≈ 43.2 分钟
SLO 99.95% → 每月允许失败 0.05% ≈ 21.6 分钟
SLO 99.99% → 每月允许失败 0.01% ≈ 4.3 分钟
错误预算消耗 = 1 -(当前 SLI 达标时间占比)
| SLO | 每月错误预算 | 每天错误预算 |
|---|---|---|
| 99.9% | ≈ 43.2 分钟 | ≈ 86.4 秒 |
| 99.95% | ≈ 21.6 分钟 | ≈ 43.2 秒 |
| 99.99% | ≈ 4.3 分钟 | ≈ 8.6 秒 |
| 99.999% | ≈ 26 秒 | ≈ 0.86 秒 |
3.3 错误预算的两种计算口径
口径一:时间口径(假设计算 99.9% = 每月宕机不超过 43 分钟)
口径二:请求口径(成功率口径:99.9% 请求成功)
注意:时间口径常用于基础设施(uptime),
请求口径更适合服务(成功率)。选择要对齐业务语义。
4. 告警策略:Multi-window / Multi-burn-rate
4.1 为什么不能用"单一阈值告警"
传统告警:SLO 掉到 99.5% 以下才报警
- 问题:等跌破目标才告警,错误预算已大量消耗
- 噪声:偶发小抖动频繁触发,On-Call 疲劳
Google SRE 方法:Burn Rate(烧钱速率)告警
用"错误预算消耗速度"而非"绝对水位"来告警
4.2 Multi-burn-rate 告警
按消耗速率分两档:
- 快速燃烧(如 14.4x):错误预算在 1 小时内烧完 5%+
→ Page(立即叫醒)
- 慢速燃烧(如 2x):预算在 1 天内烧完
→ Ticket(工作日处理)
配合 Multi-window:同一告警用长/短两个窗口同时判断
→ 既及时又不被瞬时抖动打扰
4.3 Prometheus 告警规则示例
# SLO:30 天可用性 99.9%,burn-rate 14.4(快速)告警
groups:
- name: slo-alerts
rules:
- alert: SLOAvailableBurnRateHigh
expr: |
(1 - (
sum(rate(http_server_request_count{status!~"5.."}[1h]))
/ sum(rate(http_server_request_count[1h]))
)) > (14.4 * (1 - 0.999))
for: 5m
labels:
severity: page
annotations:
summary: "SLO 错误预算快速消耗"
Multi-window 要点:同时用 1h 与 6h 两个窗口,
短窗口防延迟、长窗口防抖动误报 → 两者都触发才算真故障
5. 错误预算耗尽:冻结发布与恢复
5.1 错误预算耗尽意味着什么
错误预算耗尽 = 本月已经"用完了失败额度"
→ 应停止一切冒险动作(高风险变更),集中修复
→ 这是 Google SRE 的经典做法:错误预算驱动发布决策
5.2 冻结发布机制
触发:错误预算消耗 ≥ 100%
动作:高风险发布自动冻结(feature freeze)
- 停止金丝雀 / 全量发布(除紧急安全修复)
- 集中精力做稳定性修复
恢复:下月/下周期预算重置后解冻
注意:冻结不是"惩罚",是"预算管理"
低风险变更(依赖升级、配置回滚)仍可继续
5.3 门禁实现(CI/CD 结合)
# 发布门禁:查错误预算余额,不足则阻塞
- name: Check error budget
run: |
REMAINING=$(curl -s https://sloth.internal/api/budgets/shop-api/remaining)
if [ "$REMAINING" -le 0 ]; then
echo "错误预算已耗尽,冻结发布" && exit 1
fi
分级策略:
- 预算充足(>50%)→ 正常发布
- 预算紧张(20%~50%)→ 需要负责人审批
- 预算耗尽(<0%)→ 冻结高风险发布
6. SRE 值班与 On-Call
6.1 值班的目标与指标
On-Call 不是"24 小时待命"而是"事件响应纪律":
- 目标是尽快恢复服务(MTTR),不是背锅
- 值班质量用错误预算关联:值班做得好 = 预算消耗少
- 过度报警会赶走值班的人 → 告警质量比数量重要
6.2 值班设计要点
| 要素 | 设计 |
|---|---|
| 轮值 | 主/备,1-2 周一轮,避免长期疲劳 |
| 告警分级 | Page(立即)/ Ticket(工作时间) |
| 升级路径 | 值班→主负责人→SRE 负责人→管理层 |
| 交接 | 交接文档 + 上屏的当前状态 |
| 事后 | Blameless Postmortem,改进项闭环 |
6.3 值班与错误预算的联动
- 值班期间的高消耗事件 → 触发复盘(无论是否解决)
- 值班质量纳入评估:响应及时、恢复迅速、文档完备
- 告警噪音率是值班健康度指标(噪音高 → 告警治理)
7. 与混沌工程 / 发布门禁联动
7.1 混沌工程验证 SLO
SLO 定义了"必须保持的可靠性",混沌工程验证"是否真能保持":
- 注入故障(杀 Pod / 断网 / 加延迟)→ 观察 SLO 是否仍达标
- 演练结论反过来修正 SLO 目标或架构
- 错误预算也用于"演练是否值得":预算越紧,演练风险越高
7.2 发布门禁与 SLO 的三层联动
- 发布前:金丝雀/预览环境跑 SLO 探针(新版本可靠性预检)
- 发布中:对比新旧版本 SLI(自动回滚触发条件)
- 发布后:监控错误预算消耗速率(快速燃烧则回滚)
示例自动回滚:
金丝雀版本 P95 延迟比基线高 20% 或错误率 > 阈值 → 自动回滚
# Argo Rollouts + SLO 分析(概念)
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: slo-success-rate
spec:
metrics:
- name: success-rate
interval: 60s
failureLimit: 3
successCondition: result[0] >= 0.999
provider:
prometheus:
address: http://prometheus:9090
query: |
sum(rate(http_server_request_count{app="shop-api",status!~"5.."}[5m]))
/ sum(rate(http_server_request_count{app="shop-api"}[5m]))
8. 工具落地:Prometheus / Pyrra
8.1 工具选型
| 工具 | 用途 | 特点 |
|---|---|---|
| Prometheus | 指标采集与计算 | 事实标准 |
| Sloth | SLO 生成 Prometheus 规则 | 声明式、多窗口自动生成 |
| Pyrra | SLO 定义 + 仪表盘 | 对标 Google SRE,生成 Alert + Dashboard |
| Grafana | SLO 可视化 | 错误预算燃烧图 |
| 云厂商(AWS CloudWatch / Datadog SLO) | 托管 SLO | 少运维 |
8.2 Pyrra 定义 SLO
# slo.yaml(Pyrra):声明式 SLO
apiVersion: pyrra.dev/v1alpha1
kind: ServiceLevelObjective
metadata:
name: shop-api-availability
namespace: monitoring
spec:
target: "99.9"
window: 28d
indicator:
ratio:
errors:
metric: http_server_request_count{app="shop-api"}
grouping: [app]
filter: 'status!~"5.."'
total:
metric: http_server_request_count{app="shop-api"}
grouping: [app]
# Pyrra 根据 SLO 自动生成 Prometheus 告警规则与 Grafana Dashboard
pyrra compute slo.yaml
kubectl apply -f generated/ # 生成 Multi-window / Multi-burn-rate 告警
8.3 可视化:错误预算燃烧图
Grafana 面板:
- 错误预算剩余百分比(随时间下降的曲线)
- Burn Rate 指示条(绿/黄/红三档)
- SLO 目标线 + 实际 SLI 线(差距可视化)
- 按服务/团队下钻
日常就一句话:预算充足(绿)放心发,预算紧张(黄)谨慎发,预算耗尽(红)停手修
9. 案例与最佳实践
9.1 一个真实案例
场景:电商核心链路"下单服务",SLO = 28 天可用性 99.9%
过程:
- 初设:用当前真实成功率(99.94%)反推 SLO=99.9%,留缓冲
- 告警:Pyrra 生成 14.4x / 2x 双速率告警,接 PagerDuty
- 联动:错误预算耗尽自动冻结功能发布,只允许稳定性修复
- 验证:每月 GameDay 注入数据库延迟,确认 SLO 仍达标
结果:
- 告警量下降 60%(从"水位告警"换成"消耗速率告警")
- 团队敢发布:预算充足时放开,异常时自动刹车
- 复盘有依据:每次事件看消耗了多少预算,而非"感觉多严重"
9.2 最佳实践 Checklist
□ SLI 从用户旅程出发,单一、可度量、对用户有意义
□ SLO 基于现状设定,严于 SLA,留缓冲
□ 错误预算按请求/时间口径明确定义
□ 告警用 Burn Rate(14.4x/2x)+ Multi-window,弃用单一水位
□ 错误预算耗尽 → 冻结高风险发布,集中修复
□ On-Call 用错误预算衡量值班质量,控制告警噪音
□ 混沌演练验证 SLO,发布门禁对比新旧版本 SLI
□ Pyrra/Sloth 声明式管理 SLO,自动生成告警与面板
□ SLO 定期复盘:目标是否还合理、是否需要调整
9.3 常见坑
| 坑 | 现象 | 对策 |
|---|---|---|
| 五个九拍脑袋 | 成本失控、发布瘫痪 | 从现状反推 |
| SLI 定义不清 | 谁都测出不同数 | 统一口径 + 单一数据源 |
| 单一阈值告警 | 噪音大/发现晚 | Burn Rate + Multi-window |
| 冻结一刀切 | 安全修复也被卡 | 区分风险等级 |
| 无人看预算 | 冻结机制空转 | 自动化门禁 |
| SLO 永不更新 | 目标过时 | 季度复盘 |
9.4 一句话原则
错误预算 = "用允许失败的时间换敢于发布的底气,
钱花完了就歇一歇,把系统修好再上路。"
小结
SLO 与错误预算工程 = SLI 定义"什么算好" → SLO 设定"好到什么程度" → 错误预算算出"能承受多少失败" → Burn Rate 告警"烧得多快" → 预算耗尽"自动刹车",并与混沌演练、发布门禁、On-Call 值班构成完整的可靠性闭环。落地记住五件事:SLI 从用户旅程选、SLO 从现状反推并留缓冲、告警用消耗速率而非水位、预算耗尽冻结高风险发布、SLO 定期复盘保持合理。当"可用性"从 PPT 口号变成团队每天都在看的预算仪表盘,可靠性与发布速度就从矛盾变成了可管理的权衡——这正是 Google SRE 留给现代工程最重要的方法论遗产。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。