197|SLA、SLO 与错误预算:可用性度量、预算消耗和发布决策

架构设计与系统设计约 13 分钟阅读7,504 字符
知识库文档 198 / 251

一、引言:一次 P0 故障引发的反思

凌晨两点,告警群炸了。某核心支付接口的可用性从 99.95% 骤降至 97%。值班工程师紧急回滚、复盘、写事故报告。第二天,业务方怒气冲冲地质问:"我们签了 SLA,承诺 99.9% 可用性,这个月已经两次故障了,你们到底能不能保证?"

这个场景对许多后端工程师来说并不陌生。但问题在于:SLA 协议和实际可用性之间,到底缺了什么? 答案是缺了 SLO 和错误预算这层"工程缓冲"。SLA 是对客户的承诺,SLO 是团队内部的目标,错误预算则是连接两者的桥梁——它告诉你"在违约之前,我们还有多少犯错的空间"。

本节将带你从定义到实践,彻底理解 SLA、SLO 和错误预算三个核心概念,掌握如何用错误预算驱动发布决策,建立一套可量化的服务可靠性管理体系。


二、核心概念:SLI、SLO、SLA 的三角关系

2.1 SLI(Service Level Indicator)—— 服务等级指标

SLI 是衡量服务行为的量化指标。它是所有讨论的起点——没有 SLI,就没有 SLO,也就没有 SLA。

SLI 的数学定义:

code
SLI = (好事件数 / 总有效事件数) × 100%

比如,一个 HTTP 服务在 5 分钟内收到 10000 个请求,其中 9850 个返回了成功的响应(2xx),那么:

code
SLI = 9850 / 10000 = 98.5%

常见的 SLI 类别:

类别 指标 示例
可用性 成功请求比例 HTTP 2xx / 总请求
延迟 请求耗时分布 P50/P95/P99 延迟
吞吐量 每秒处理量 QPS / TPS
正确性 数据准确性 幂等写入成功率
持久性 数据不丢失比例 写入后能读取的比例

SLI 的正确度量方式:

一个常见的误区是把"服务没挂"等同于"服务可用"。实际上,SLI 需要精确到用户视角:

  • ❌ 错误做法:监控 CPU 使用率、内存占用——这些是内部指标,用户感知不到
  • ✅ 正确做法:监控请求成功率、响应延迟、业务错误率——这是用户能感受到的

SLI 的聚合粒度:

SLI 通常按时间窗口聚合,常见的选择有:

  • 滚动窗口:过去 5 分钟、30 分钟
  • 日历窗口:自然天、自然周、自然月(与 SLA 对齐)

选择窗口大小时有个权衡:窗口太小,噪声大、误报多;窗口太大,敏感性差、发现问题慢。Google SRE 团队推荐30 天滚动窗口作为 SLO 的计算基础,这是经过大量实践验证的经验值。

2.2 SLO(Service Level Objective)—— 服务等级目标

SLO 是 SLI 的目标值,是团队内部对服务质量的承诺。它回答了"我们期望服务达到什么水平"。

SLO 的典型表达:

code
"99.9% 的请求,在 30 天内,响应时间 ≤ 200ms"

拆解这个 SLO:

  • SLI:P99 响应延迟
  • 目标值:≤ 200ms
  • 达标率:99.9%
  • 时间窗口:30 天

SLO 不是 100%:

一个关键认知是:永远不要设 100% 的 SLO。原因有三:

  1. 物理上不可能:磁盘会坏、网络会断、机房会停电,100% 不可达
  2. 成本过高:从 99.9% 到 99.99% 可用性,成本可能增加 10 倍甚至更多
  3. 阻碍创新:追求 100% 意味着零风险容忍,导致发布停滞、技术债堆积

SLO 的层级设计:

对于复杂系统,建议设计多层级 SLO:

code
- 顶级 SLO(面向用户):"99.9% 支付请求在 30 天内成功"
- 二级 SLO(面向依赖):"99.95% 数据库查询在 1s 内完成"
- 三级 SLO(面向组件):"消息队列积压不超过 1000 条"

当顶级 SLO 达标时,我们不需要逐层排查;当顶级 SLO 不达标时,逐层下钻定位根因。

2.3 SLA(Service Level Agreement)—— 服务等级协议

SLA 是对外承诺,是服务提供方与客户之间的商业协议。它包含明确的处罚条款。

SLA 与 SLO 的关键区别:

维度 SLO SLA
受众 内部团队 客户/业务方
性质 工程目标 法律/商业协议
要求 应比 SLA 更严格 通常比 SLO 宽松
后果 内部复盘、改进 赔款、违约、失去客户
变更 团队可自行调整 需双方协商

SLA 的典型结构:

code
服务可用性:≥ 99.9%
月度停机补偿:
  - 99.0% ~ 99.9%:减免 10% 费用
  - 95.0% ~ 99.0%:减免 30% 费用
  - < 95.0%:减免 100% 费用

SLO 与 SLA 的安全带:

Google SRE 的建议是:SLO 应该比 SLA 更严格,留出安全缓冲。比如,如果 SLA 承诺 99.9%,那么 SLO 可以设为 99.95%。这个 0.05% 的差距就是安全边际,确保 SLA 不违约。

2.4 三角关系图

code
        ┌─────────────────────────────────┐
        │          SLA(对外合同)           │
        │     "99.9% 可用性,否则赔款"       │
        │  ┌───────────────────────────┐  │
        │  │    SLO(内部目标)           │  │
        │  │   "99.95% 可用性"          │  │
        │  │  ┌─────────────────────┐  │  │
        │  │  │ 错误预算 = 0.05%     │  │  │
        │  │  │ (允许犯错的空间)     │  │  │
        │  │  └─────────────────────┘  │  │
        │  └───────────────────────────┘  │
        └─────────────────────────────────┘
              ↑ 由 SLI 度量驱动

文章配图
文章配图


三、SLI 的选择与度量:从哪里开始?

3.1 选择 SLI 的原则

选择 SLI 不是越多越好,Google SRE 给出的原则是:

1. 从用户视角出发

不要问"系统健康吗",要问"用户满意吗"。一个服务可能 CPU 满载、内存泄漏,但如果用户请求都能正常返回,从 SLO 角度看它仍然是"可用"的。

2. 覆盖请求生命周期的关键节点

一个典型的 HTTP 请求全链路:

code
客户端 → DNS → 负载均衡 → 应用 → 缓存 → 数据库 → 响应

每个环节都可能出问题,但 SLI 应该聚焦在用户能感知到的、端到端的结果上。比如关注"请求是否成功返回"而不是"数据库连接池是否用满"。

3. 用性能分布代替平均值

平均值是最大的骗子。假设一个服务有 100 个请求,99 个 10ms 返回,1 个花了 10s。平均值是 109.9ms,"看起来"还不错。但那个 10s 的用户体验极差。

所以 SLI 应该用百分位数:

  • P50:一半请求的延迟
  • P95:95% 请求的延迟(常见 SLO 目标)
  • P99:99% 请求的延迟(关注长尾)

3.2 关键 SLI 的度量方法

可用性 SLI:

code
可用性 = (成功请求数 / 总请求数) × 100%

这里"成功"的定义需要仔细考虑。对于一个电商下单接口,以下情况算成功还是失败?

  • HTTP 200,但返回了"系统繁忙"的业务错误码 → 应该算失败
  • HTTP 500,但落在了无业务流量的探活端点 → 应该排除
  • 请求超时,客户端未收到响应 → 应该算失败

所以,可用性 SLI 必须对齐业务语义,不能只看 HTTP 状态码。

延迟 SLI:

code
延迟达标率 = (延迟 ≤ 阈值的请求数 / 总请求数) × 100%

延迟分布通常呈现长尾特征。在分布式系统中,一次用户请求可能涉及数十次 RPC 调用,如果每个 RPC 的 P99 延迟是 100ms,那么端到端 P99 延迟可能远超 100ms(因为尾延迟叠加效应)。

3.3 多 SLI 组合

一个服务通常需要多个 SLI:

code
服务:用户支付接口
SLI 集合:
  1. 可用性 SLI:请求成功率 ≥ 99.95%
  2. 延迟 SLI:P99 延迟 ≤ 500ms,达标率 ≥ 99.9%
  3. 数据正确性 SLI:幂等写入成功率 ≥ 99.99%

多个 SLI 之间可能存在冲突。比如,为了提高可用性,你可能会增加重试——但重试会提高延迟。所以 SLI 设计需要权衡,不能孤立地优化某一个指标。


四、SLO 的设计原则:如何设定合理的目标

4.1 SLO 的目标值应该定多少?

这是最常被问到的问题。答案不是拍脑袋,而是基于以下因素:

1. 用户期望

用户对延迟的感知:

  • 100ms:感觉"即时"
  • 300ms:感觉"很快"
  • 1000ms:感觉"还行"
  • 3000ms:感觉"有点慢"
  • 10000ms:失去注意力

所以延迟 SLO 通常设在 200ms-500ms 之间。

2. 系统能力

你需要了解系统当前的实际表现。如果 P99 延迟经常超过 1s,设 200ms 的 SLO 是自欺欺人。

3. 依赖链的可靠性

如果服务依赖 5 个下游服务,每个的可用性都是 99.9%,那么:

code
本服务的最大可用性 = 0.999^5 = 99.5%

这意味着 SLO 不可能超过 99.5%,除非依赖方提升可靠性或增加降级策略。

4. 成本约束

每提升一个"9"的可用性,成本大致翻倍:

  • 99.9%(三个 9):年停机 8.76 小时,常规架构即可
  • 99.99%(四个 9):年停机 52.56 分钟,需要异地多活
  • 99.999%(五个 9):年停机 5.26 分钟,需要全自动故障转移

文章配图
文章配图

4.2 SLO 的测量周期

Google SRE 推荐使用滚动窗口而非日历窗口:

窗口类型 优点 缺点
30 天滚动窗口 平滑、对短暂故障不敏感 历史故障影响持续 30 天
7 天滚动窗口 更敏感 噪声大
自然月 与 SLA 对齐 月初重置,月末压力大

实务中,很多团队使用双层窗口:30 天窗口用于 SLO 合规判断,7 天窗口用于快速告警。

4.3 SLO 的告警策略

有了 SLO 后,告警应该基于错误预算消耗速率,而不是简单的"可用性低于阈值"。

多窗口多燃烧率告警是 Google 推荐的方案:

告警级别 窗口 燃烧率 含义
关键告警 1h 14.4x 2% 错误预算在 1 小时内烧完
警告告警 6h 6x 5% 错误预算在 6 小时内烧完

"燃烧率"指的是错误预算相对于均匀消耗的消耗速度。如果均匀消耗,30 天的错误预算每天消耗 1/30 ≈ 3.33%。如果燃烧率是 14.4x,意味着实际消耗速度是均匀消耗的 14.4 倍。

文章配图
文章配图


五、错误预算:SRE 的核心武器

5.1 什么是错误预算?

错误预算(Error Budget)是 SLO 允许的最大不可靠量。它回答了:"在 SLO 范围内,我们还能承受多少故障?"

计算公式:

code
错误预算 = 1 - SLO 目标值

如果 SLO 是 99.9% 可用性,那么:

code
错误预算 = 1 - 0.999 = 0.001 = 0.1%

这意味着在测量周期内,最多允许 0.1% 的请求失败。

换算成具体数量:

假设一个服务每分钟处理 100 万个请求,30 天总共处理约 43.2 亿个请求:

code
最大允许失败请求数 = 43.2 亿 × 0.1% = 432 万次失败

432 万次听起来很多,但如果一次故障持续 5 分钟,每分钟产生 100 万个失败请求,一次故障就消耗 500 万次失败,直接超出预算。

5.2 错误预算的消耗分析

错误预算不是均匀消耗的。典型的消耗模式:

code
错误预算消耗曲线:
 100%|████████████████████████████████████████
     |                                        |
     |                                        |
     |                    ████ ← 故障A         |
     |                    ████                 |
  50%|                    ████                 |
     |                    ████                 |
     |                                        |
     |                                        ██ ← 故障B
     |                                        ██
   0%|________________________________________|__
     Day1                                    Day30

关键观察:

  • 大部分时间错误预算消耗很少
  • 少数几次故障消耗了大部分预算
  • 故障消耗的速度远快于预算恢复的速度

文章配图
文章配图

5.3 错误预算的剩余量计算

code
剩余预算 = 1 - (实际不可用时长 / 允许的不可用时长)

30 天窗口内,99.9% SLO 允许的最大不可用时长为:

code
30 × 24 × 60 × 0.001 = 43.2 分钟

如果已经发生了 15 分钟的故障:

code
剩余预算 = 1 - (15/43.2) = 65.3%

六、错误预算驱动的发布决策

这是错误预算最有价值的应用:用数据驱动发布策略。

6.1 决策框架

code
错误预算剩余 > 50%:正常发布,可以加速
错误预算剩余 20% ~ 50%:谨慎发布,冻结高风险变更
错误预算剩余 < 20%:冻结所有发布,全力保障可靠性
错误预算耗尽(< 0%):进入紧急状态,优先恢复可靠性

文章配图
文章配图

6.2 实际决策流程

场景 1:预算充足(> 50%)

code
时间:月初
错误预算剩余:80%
决策:正常发布节奏
  - ✅ 常规功能发布
  - ✅ 架构变更
  - ✅ 基础设施升级

场景 2:预算紧张(20% ~ 50%)

code
时间:月中
错误预算剩余:35%
原因:上周一次故障消耗了 50% 预算
决策:谨慎发布
  - ✅ 缺陷修复
  - ⚠️ 功能发布需额外审批
  - ❌ 大规模架构变更推迟

场景 3:预算耗尽(< 0%)

code
时间:月底
错误预算剩余:-15%
原因:本月两次重大故障
决策:冻结发布
  - ✅ 仅允许紧急安全修复
  - ❌ 所有功能发布暂停
  - ❌ 所有非紧急变更冻结
  - 🎯 团队全力投入可靠性改进

6.3 产品团队与 SRE 的博弈

传统模式下,产品团队和 SRE 团队存在天然冲突:

code
产品团队:发布!发布!发布!
SRE 团队:慢点!系统不稳定!

错误预算解决了这个矛盾:

code
产品团队:我想发布新功能
SRE 团队:当前错误预算剩余 45%,功能发布可以,但架构变更需要推迟
产品团队:为什么?
SRE 团队:因为架构变更的风险更高。这是数据,不是个人意见。

错误预算把"可靠性 vs 速度"的感性的对立,变成了基于数据的理性决策。

文章配图
文章配图


七、进阶:多窗口 SLO 与复合 SLI

7.1 为什么需要多窗口?

单一的 30 天窗口有个问题:对短期故障反应迟钝。

假设一个服务在过去 29 天零故障,第 30 天发生 40 分钟的故障(对于 99.9% SLO,允许 43.2 分钟)。30 天窗口的 SLO 仍然达标,但实际上第 30 天的用户经历了很差的服务。

多窗口方案:

窗口 用途 示例
30 天 SLO 合规判断 99.9%
7 天 短期趋势监控 99.5%
1 天 快速告警 99.0%

7.2 复合 SLI 的 SLO

实际系统中,一个服务的 SLO 往往是多个 SLI 的复合:

code
SLO:支付接口服务质量
├── 可用性:99.95%
├── 延迟(P99):≤ 500ms,达标率 99.9%
└── 数据正确性:100%(零容忍)

对于复合 SLO,错误预算取最严格的那个:

code
错误预算 = min(可用性预算, 延迟预算, 正确性预算)

如果可用性预算还剩 60%,但延迟预算只剩 10%,那么整体错误预算就是 10%。

7.3 依赖链的错误预算传递

当一个服务依赖下游时,错误预算需要向下传递:

code
服务 A(SLO 99.9%) → 服务 B(SLO 99.95%) → 服务 C(SLO 99.99%)

下游服务需要比上游更可靠,因为错误会累积:

code
如果服务 B 的可用性 = 99.9%,服务 C 的可用性 = 99.9%
服务 A 的最大可用性 = 0.999 × 0.999 = 99.8%

这低于服务 A 的 SLO 99.9%,说明依赖链的可靠性需要重新设计。

文章配图
文章配图


八、实践案例:从度量到决策的闭环

8.1 案例背景

某电商平台的核心交易接口,日均请求量 5 亿次。SLA 承诺 99.9% 可用性,SLO 设为 99.95%。

8.2 度量体系搭建

Step 1:定义 SLI

code
可用性 SLI = (返回非错误响应 / 总请求数) × 100%
  - 错误响应包括:HTTP 5xx、业务错误码、超时
  - 排除:健康检查端点、内部探测请求

延迟 SLI = (P99 延迟 ≤ 300ms 的分钟数 / 总分钟数) × 100%
  - 按分钟聚合,超过阈值的分钟数即为不可用

Step 2:建立监控

基于 Prometheus + Grafana 搭建:

promql
# 可用性 SLI(30天滚动窗口)
sum(rate(http_requests_total{status!~"5.."}[30d]))
/
sum(rate(http_requests_total[30d]))

# 错误预算消耗速率(1小时窗口)
(sum(rate(http_requests_total{status=~"5.."}[1h]))
/
sum(rate(http_requests_total[1h])))
/
(1 - 0.9995)

Step 3:配置告警

多窗口多燃烧率告警:

  • 1h 窗口,燃烧率 > 14.4x → 紧急告警
  • 6h 窗口,燃烧率 > 6x → 警告告警

8.3 一次真实的故障复盘

事件: 某次发布引入了慢查询,导致数据库连接池耗尽,交易接口可用性从 99.98% 降至 99.2%,持续 25 分钟。

影响分析:

code
本月错误预算总额:30 × 24 × 60 × 0.05% = 21.6 分钟
本次故障消耗:25 分钟
错误预算剩余:-3.4 分钟(已耗尽!)

决策:

  1. 立即回滚变更
  2. 冻结所有后续发布
  3. 团队接下来两周的核心工作:加强 SQL 审核流程、增加连接池监控、补充慢查询告警
  4. 错误预算恢复为正后,逐步恢复发布节奏

8.4 度量体系的效果

实施半年后:

  • 故障平均恢复时间(MTTR)从 45 分钟降至 15 分钟
  • 非紧急发布被冻结的次数:3 次(每次冻结后系统可靠性显著改善)
  • 产品团队从"为什么不让我发布"变成"错误预算还剩多少?我能不能发布?"

文章配图
文章配图


九、总结

SLA、SLO 和错误预算构成的三角体系,是 SRE 方法论中最核心的部分。它解决了传统运维中两个最棘手的问题:

  1. 可靠性到底"够不够"? —— 用 SLO 量化,用 SLI 度量
  2. 发布速度 vs 稳定性如何取舍? —— 用错误预算做数据驱动的决策

三个关键洞见:

  • 永远不要设 100% 的 SLO:完美是优秀的敌人,过度追求可靠性会扼杀创新
  • 错误预算是一种"可消耗资源":用光之后必须"偿还"——通过可靠性投入恢复预算
  • SLO 是团队内部契约:它让产品、开发和运维在同一个数据基础上对话,而不是互相甩锅

对于技术专家和架构师而言,掌握这套体系意味着你能量化地思考可靠性,而不仅仅是"我感觉系统挺稳定的"——这才是面试官真正想听到的答案。


十、面试官提问

以下问题从面试官视角出发,模拟真实面试场景中的追问。请先独立思考,再看参考答案。

Q1:你们团队的 SLO 是 99.9%,连续两个月都达标。但用户投诉说"系统经常卡顿"。你怎么解释这个矛盾?

追问: 如果让你重新设计 SLI,你会怎么改?


Q2:假设你的服务 SLO 是 99.99%,本月还剩 3 天,错误预算已经耗尽。产品经理坚持要在这 3 天内发布一个重要功能,否则错过运营活动窗口。你怎么办?

追问: 如果产品总监说"我承担这个风险",你作为 SRE 负责人会同意吗?


Q3:一个服务依赖 5 个下游,每个下游的 SLO 都是 99.9%。如果上游的 SLO 也是 99.9%,理论上可行吗?如果不可行,你有哪些解决方案?

追问: 如果有一个下游的 SLO 是 99.5%,其他都是 99.9%,你的错误预算会怎么分配?


Q4:你设计了一个多窗口 SLO 告警系统。某天凌晨,1 小时窗口的燃烧率告警触发了,但 30 天窗口的 SLO 仍然达标。你作为值班工程师,会怎么处理?

追问: 如果这类告警每周都触发,但 30 天 SLO 从未真正违反,告警策略是否需要调整?怎么调整?


Q5:你们的 SLA 承诺 99.9%,SLO 设了 99.95%。但最近半年 SLA 从未违约,SLO 却被违反过 3 次。这正常吗?SLO 和 SLA 之间的安全边际应该设多少?

追问: 如果竞品把 SLA 从 99.9% 提升到 99.99%,你们的 SLO 和 SLA 需要怎么调整?你如何评估这个调整的成本?


Q6:你如何向非技术背景的业务方解释"错误预算"这个概念?请用一段不超过 3 分钟的话说明。

追问: 如果业务方说"那你们把 SLO 设成 99%,我们就有更多错误预算可以做更多发布了",你怎么回应?


Q7:设计一个错误预算看板,你会包含哪些关键指标?分别面向哪些角色?

追问: 如果看板上的错误预算突然归零,但没有任何告警触发,你首先怀疑什么?


(参考答案见文末折叠区)

📝 点击展开参考答案

A1: 这说明 SLI 没有覆盖用户真正的痛点。99.9% 可用性只衡量"请求是否成功",但用户抱怨的"卡顿"实际是延迟问题。需要增加延迟 SLI(如 P95 延迟 ≤ 1s 的达标率),可能延迟 SLO 早已违反。

A2: 核心是"谁来承担风险"。SRE 的职责是如实报告风险,而不是替业务做决策。可以启动"风险接受流程":产品总监书面确认已知风险、接受可能的 SLA 违约后果。但需要明确:如果 SLA 违约导致客户索赔,这笔成本由业务方承担。

A3: 理论上不可行。5 个下游各 99.9%,上游最大可用性 = 0.999^5 ≈ 99.5%。解决方案:增加降级策略(核心链路保证、非核心降级)、提升下游 SLO、引入冗余(多副本、多机房)、合理设置超时和熔断。

A4: 短期燃烧率告警是"预警信号",不代表 SLO 必然违反。但需要立即排查:是否真的发生了故障?如果是误报(如流量突增导致统计偏差),需要调整告警阈值。如果每周都触发但从不违反 SLO,说明告警太敏感,可以在保持 1h 窗口的同时,提高燃烧率阈值(如从 14.4x 提到 20x)。

A5: 这反映 SLO 作为"内部预警"的正常表现。SLO 被违反 3 次但 SLA 未违约,说明安全边际有效。安全边际通常设为 SLA 的 2-5 倍——即如果 SLA 是 99.9%(允许 43.2 分钟/月停机),SLO 可设为 99.95%(允许 21.6 分钟/月)。竞品提升 SLA 时,需要评估:我们的系统当前实际能力能支撑更高的 SLA 吗?如果不能,需要多大投入?如果投入大于收益,可以选择不跟进,而是强化其他差异化优势(如更低延迟、更丰富的功能)。

A6: "错误预算就像一个'犯错额度'。我们承诺系统 99.9% 的时间正常工作,那剩下的 0.1% 就是我们可以'犯错'的时间——系统出故障、发布出问题,都在这个额度里扣。如果额度用完了,就不能再冒险发布新功能了,要先保证系统稳定。如果额度还有富余,我们就可以更大胆地迭代。"

如果业务方提议降低 SLO:"降低 SLO 确实能增加错误预算,但代价是用户能感受到更多的故障。99% 可用性意味着每月可以有 7 小时停机——用户每个月都经历 7 小时的不可用,他们还会用我们的产品吗?所以 SLO 的设定是一个商业决策,需要平衡用户体验和迭代速度。"

A7: 看板分层设计:

  • C 级别看板:SLA 合规状态(红/黄/绿)、本月错误预算剩余百分比、同比环比趋势
  • 技术经理看板:各服务 SLO 达标状态、错误预算消耗分布、Top 故障消耗
  • 工程师看板:实时 SLI 趋势、燃烧率曲线、具体故障事件时间线

如果看板归零但无告警:首先怀疑告警规则配置错误——可能告警的 PromQL 查询的是另一个时间窗口,或者告警规则被静默、被禁用。也可能是看板的数据源和告警系统使用了不同的数据管道。