03 可靠性目标:SLI / SLO / SLA
概述#
SRE 体系最核心的方法论是量化可靠性。没有 SLI/SLO/SLA 这一套度量框架,可靠性就只能靠感觉——"最近好像不太稳定""这个服务应该可用性很高"。本章从 SLI 选型到 SLO 制定到 SLA 落地,完整建立可靠性量化的知识体系。配合可观测性培养教材(M1-M6)的顶层框架和 SLO 实战文章的工程细节。
读完本章,你应能回答:为什么不用平均延迟?SLO 凭什么是 99.9% 不是 100%?SLA 和 SLO 的缓冲带有什么用?SLI 选取的"用户视角"具体怎么落地?
一、三个概念的定义与关系#
SLI(Service Level Indicator,服务等级指标)#
SLI 是服务质量的具体测量值。它是一个数字,比如"过去 5 分钟 P99 延迟是 230ms"、"过去 1 小时成功率是 99.7%"。
SLI 的核心要求:站在用户视角。CPU 使用率、内存占用、Pod 重启次数这些是基础设施指标,不是 SLI。SLI 衡量的是用户实际感受到的东西——请求成功了没有、页面加载快不快。
判断一个指标是不是合格的 SLI,问三个问题:
- 这个指标和用户感受到的服务质量直接相关吗?
- 这个指标变差时,用户会察觉到吗?
- 这个指标改善时,用户会受益吗?
三个都是"是"——合格 SLI;只要有一个"否",就不是 SLI。例如 CPU 使用率:CPU 80% 时用户可能完全无感(合格 SLI 第一条就过不了);Redis 内存使用率 70% 时用户依然秒级响应(同样不是 SLI)。这些是原因型指标,留给排障下钻用,不进 SLO 体系。
SLO(Service Level Objective,服务等级目标)#
SLO 是给 SLI 定的目标值。比如"月度成功率 ≥ 99.9%""P99 延迟 ≤ 500ms"。SLO 是一个承诺,但不是 100% 的承诺——它明确留出了允许失败的空间。
SLO 不是 SRE 自己定的,是 SRE + 业务方共同协商的结果。SRE 提供技术可行性(系统能达到什么水平),业务方提供用户期望(用户能接受什么水平),SLO 落在两者之间——略高于历史水平、略低于系统能力上限。
SLA(Service Level Agreement,服务等级协议)#
SLA 是在 SLO 基础上叠加了法律/商业后果的正式协议。如果实际表现低于 SLA,通常涉及赔偿(退费、积分、违约金等)。
SLA 不是所有服务都有——内部服务通常没有 SLA(没有赔付对象),只有对外服务(云产品、SaaS、对客 API)才需要 SLA。但 SLO 对所有服务都该有。
三者关系#
SLI(测量值) → 用来验证 → SLO(目标值) → 违约触发 → SLA(赔付条款)
↑ ↑
|严格递进:SLI 不准 → SLO 失真 → SLA 误赔 |
| |
└── 测量层 ───────── 决策层 ───────────── 商业层 ──────────┘一套完整的可靠性体系是这样运作的:
- 用 SLI 持续测量服务质量
- 用 SLO 设置目标(比用户期望略高、比系统能力略低)
- 用 SLA 对外承诺(含违约条款,通常比 SLO 更宽松)
- 用 Error Budget 管理 SLO 余量,驱动发布和告警决策
关键公式:SLO 不能等于 SLA。SLO 是内部目标(紧),SLA 是对外承诺(松)。比如一个支付服务的 SLO 是 99.95%,但 SLA 承诺 99.9%,中间差了 0.05% 的缓冲——这 0.05% 就是 SRE 团队的操作空间。如果 SLO = SLA,意味着 SLO 一旦破线就要赔付,SRE 没有任何调整余地。
举个反面案例:某 SaaS 公司把 SLO 和 SLA 都设成 99.9%,结果某月发生一次 30 分钟故障直接触发 SLA 违约,赔了 80 万。复盘发现:SLO 应该明显严于 SLA(视业务留半个到一个九的缓冲),给团队预留出"内部能感知问题、主动修复"的时间窗口。
二、SLI 选型:四类核心指标#
1. 延迟(Latency)#
衡量请求从发出到收到响应的时间。不要用平均值,用分位数。
| 分位数 | 含义 | 使用场景 |
|---|---|---|
| P50 | 50% 的请求比这个值快 | 参考指标,不进 SLO |
| P95 | 95% 的请求比这个值快 | 通用 API |
| P99 | 99% 的请求比这个值快 | 核心服务 |
| P999 | 99.9% 的请求比这个值快 | 支付/交易等对尾延迟极度敏感的场景 |
为什么平均延迟不可用?假设 99% 的请求 10ms 返回,1% 的请求 10s 超时。平均 = (99×10 + 1×10000) / 100 = 110ms——看起来还好。但 P99 = 10000ms——那 1% 的用户在受苦。平均值掩盖长尾。
更进一步,一些团队用 P50 + P99 双指标:
- P50 反映"大多数用户体验"
- P99 反映"尾部长尾用户体验"
两者都达标才算 SLO 通过。这样能避免"P50 很好但 P99 极差"的隐性退化。
PromQL 示例:
histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, job))
# 另一种延迟 SLI:超过阈值(>500ms)的慢请求比例 = 1 - 快请求占比
# 注意 le="0.5" 桶算出的是"≤500ms 的快请求占比",取 1 - 才是"慢请求占比"
1 - (
sum(rate(http_request_duration_seconds_bucket{le="0.5"}[5m]))
/
sum(rate(http_request_duration_seconds_count[5m]))
)为什么用"超过阈值的比例"而不是 P99 值:P99 是个绝对值(如 800ms),但用户体验是相对的——"800ms 算慢"对搜索 API 和支付 API 是不同的。直接衡量"超过 SLA 阈值的请求比例"更贴近用户感受。例如 SLO 是"99% 的请求 < 500ms",等价于"超过 500ms 的请求比例 < 1%"。
2. 错误率(Error Rate)#
error_rate = 失败请求数 / 总请求数定义"失败"需要明确口径:
- HTTP 5xx:服务端错误,记失败
- HTTP 4xx:客户端错误,通常不记失败(但需视业务而定——如果 429 限流是服务端容量不足导致,应记失败)
- 超时:记失败
- 业务错误码(如"余额不足"):不记失败(这是正常业务结果)
- 连接被拒、DNS 解析失败:记失败
实际项目中 4xx 处理是最容易踩坑的。某团队把所有 4xx 都算成失败,结果一次客户端 bug 触发大量 400 Bad Request,错误率告警误报了一周。正确做法:
- 401/403(未授权/禁止):客户端问题,不记失败
- 404(未找到):可能是客户端 bug 也可能是正常"资源不存在",看业务
- 429(限流):服务端容量问题,记失败
- 499(客户端主动断开,多因服务端响应太慢导致客户端放弃):记失败
- 400(参数错误):客户端问题,不记失败
# 错误率 SLI 的 PromQL(只算 5xx)
sum(rate(http_requests_total{status=~"5.."}[5m]))
/
sum(rate(http_requests_total[5m]))
# 严格版:(5xx + 429 + 超时) / 总请求
# 分子必须加括号——PromQL 中 / 优先级高于 +,不加括号会算成 5xx + (超时/总数),结果错误
(
sum(rate(http_requests_total{status=~"5..|429"}[5m]))
+
sum(rate(http_request_timeout_total[5m]))
)
/
sum(rate(http_requests_total[5m]))3. 可用性(Availability)#
availability = 成功请求数 / 总请求数 = 1 - error_rate可用性 SLI 和错误率 SLI 经常是等价的,但某些场景需要分开:
- 服务返回 200 但内容为空(业务层失败)→ 错误率 SLI 看不出来,需要单独的可用性检查
- 服务超时不返回任何状态码 → 两种 SLI 都需要覆盖
另一种"可用性"的常见定义是基于时间:服务在统计窗口内"在线"的时间比例。这种口径适合基础设施(如数据库、消息队列),不适合请求-响应式服务。Google SRE Book 推荐用"请求级可用性"而非"时间级可用性"——前者更贴近用户感受。
4. 吞吐量(Throughput)#
throughput = 请求数 / 时间窗口(如 QPS、RPM)吞吐量通常不作为 SLO 的 SLI(因为它是容量指标,不是用户体验指标),但它是容量规划和瓶颈分析的关键数据。
某些场景下吞吐量也间接影响用户体验——当 QPS 接近系统上限时,延迟会显著上升。这种场景可以把"吞吐量达到阈值时的延迟表现"作为复合 SLI。
复合 SLI#
复杂场景需要多个指标组合。例如支付服务:
支付成功 SLI = (HTTP 200 返回) AND (业务码 = SUCCESS) AND (延迟 < 3s)复合 SLI 的实现需要应用层埋点配合——把"成功"这个语义在代码里精确写出来。PromQL 表达:
# 三条件都满足才算成功的复合 SLI
sum(rate(payment_requests_total{http_status="200", biz_code="SUCCESS", duration_le="3"}[5m]))
/
sum(rate(payment_requests_total[5m]))SLI 选取原则#
- 用户视角优先:CPU 高 ≠ 用户受影响,不要用系统指标作 SLI
- 2-5 个即可:一个服务超过 5 个 SLI 难以管理,聚焦最影响用户的核心维度
- 能被精确测量:如果你的监控系统算不出准确的成功率,那这个 SLI 不成立
- 与 SLO 窗口对齐:SLI 的测量窗口要支持 SLO 的评估周期(通常 30 天滚动)
- 避免高基数:SLI 标签不要带 user_id、order_id 等高基数维度,否则 Prometheus 会 OOM
- 每个 SLI 必须有 owner:没有 owner 的 SLI 是孤儿指标,出问题没人修
参考可观测性培养教材 M5:黄金信号 / RED / USE 方法论——SLI 选取的方法论基础。M1-M6 回答了"怎么看系统",本章回答"怎么用量化指标驱动决策"。
SLI 选取的常见误区#
- 用基础设施指标代替用户体验指标:CPU 使用率高不一定导致用户受影响,不适合作为 SLI
- SLI 太多:一个服务超过 5 个 SLI 就难以管理,聚焦在最影响用户的 2-3 个
- 忽略长尾用户:平均延迟良好不代表没有用户在受苦
- 只看成功率不看延迟:成功但慢得无法接受也是失败
- SLI 没有上下文:99% 成功率对内部工具够用,对支付 API 是灾难——SLI 必须和服务等级匹配
三、SLO 制定:为什么不能是 100%#
"99.9% 够不够?"#
99.9%(三个九)的月度 SLO,意味着每月允许约 43 分钟的不可用时间:
允许不可用 = (1 - 0.999) × 30天 × 24h × 60min
= 0.001 × 43200 min
= 43.2 分钟/月| SLO | 每年停机时间 | 每月停机时间 | 适用场景 |
|---|---|---|---|
| 99% | 3.65 天 | 7.2 小时 | 内部工具 |
| 99.5% | 1.83 天 | 3.6 小时 | 一般业务服务 |
| 99.9% | 8.76 小时 | 43.2 分钟 | 核心业务服务 |
| 99.95% | 4.38 小时 | 21.6 分钟 | 核心交易 |
| 99.99% | 52.6 分钟 | 4.32 分钟 | 支付/对账 |
| 99.999% | 5.26 分钟 | 26.3 秒 | 电信级基础设施 |
注意这张表里的"停机时间"是按 100% 不可用算的——实际故障通常是"部分用户受影响"或"延迟升高但没完全挂",所以同样的 SLO 在实际场景下能容忍的"故障时长"比表里更长。例如 99.9% 月度预算 43 分钟,如果一次故障只影响 10% 用户,那这次故障可以持续 430 分钟才耗尽预算。
为什么不能设 100%#
1. 成本指数级增长。从 99.9% 到 99.99%,每增加一个九,成本通常翻 3-5 倍——需要多活架构、更严格的发布流程、更冗余的硬件、更多的 on-call。
| 从→到 | 工程投入 | 典型新增成本 |
|---|---|---|
| 99% → 99.9% | 监控告警 + 自动恢复 | +1 名 SRE |
| 99.9% → 99.99% | 多活 + 灰度发布 + 全链路压测 | +3-5 名 SRE + 30% 硬件 |
| 99.99% → 99.999% | 异地多活 + 自动切流 + 7×24 NOC | 翻倍人力 + 翻倍硬件 |
2. 边际收益递减。用户感知不出来 99.99% 和 99.999% 的区别(后者每年只多 47 分钟可用),但付出的工程成本是天壤之别。
3. 阻碍创新。追求 100% 意味着任何变更都有风险,最终不敢发布,系统变成化石。Google 内部有个观察:SLO 设得过高的团队,反而比 SLO 适中的团队出更多事故——因为发布慢导致每次发布改动大,回归测试覆盖不住。
4. 100% 客观上不存在。即使是 Google、AWS 也不做 100%——因为依赖链上任何一个环节(DNS、网络、硬件)都可能出问题,而这些问题不在你控制范围内。
5. 错误预算是创新的空间。允许失败意味着允许尝试——新功能上线、架构重构、技术债清理都需要消耗一定的错误预算。没有错误预算等于没有试错空间。
SLO 制定的正确思路#
- 先问用户期望。你的用户能接受多大程度的不可用?内部知识库和支付接口的答案完全不同。
- 再看历史数据。过去 3 个月实际达到的水平是多少?SLO 应该略高于历史水平(有挑战性),但不能脱离现实。
- 计算成本。每提高一个九需要投入多少工程资源?这个投入有没有更好的去处?
- 用数字说话。"每月允许 43 分钟不可用"比"99.9%"更好沟通——业务方容易理解具体时间。
- 分服务等级。不同服务设不同 SLO。核心交易链路 99.99%,辅助功能 99.9%,内部工具 99%——一刀切是错误的。
- 留缓冲带。SLO 不能等于历史最佳水平,要留 10-20% 缓冲应对突发流量和意外故障。
SLO 推进路线(从 SLO 实战文章提取)#
第一阶段(1-2 个月):只观察,不告警
→ 建 Dashboard,让团队熟悉指标
→ 修正 SLI 计算逻辑(数据对不对)
→ 找出数据异常点,理解为什么
→ 让业务方先看到数字,建立共识
第二阶段(3-4 个月):引入告警,轻量级
→ 只配 P1 告警(快速消耗)
→ 每月做 Error Budget 回顾
→ 建 SLO 违规复盘流程
→ 此时团队对指标有信任,告警才有效
第三阶段(5 个月+):SLO 影响决策
→ Error Budget 冻结策略生效
→ 发布决策参考 Error Budget
→ 每季度回顾并调整 SLO 目标
→ SLO 进 OKR,与团队绩效挂钩这套推进路线的核心思想是"先建立信任再约束行为"。第一阶段直接上 SLO 告警会触发团队反弹——"我们的指标还没准就告警,是噪音"。先观察 2 个月让团队理解指标含义、修正计算 bug,再上告警,最后才让 SLO 影响发布决策。
来自 A 旗舰可观测性体系的实践经验#
在实际落地中,7 路逐跳测绘发现了几个关键教训:
- 埋点先行于 SLO。没有合适的埋点(counter/histogram),SLO 是空中楼阁。首批 3 个 SLI(登录成功率、对话完成率、沙箱拉起成功率)在影子运行阶段就暴露了埋点缺口。
- SLI 计算也需要 Recording Rules。复杂的 PromQL 直接算会导致 Dashboard 和告警都慢。预计算成
job:slo_errors_per_request:ratio_rate5m这样的 Recording Rule,查询性能提升 10 倍以上。 - 合成监控兜底真实流量盲区。半夜无用户流量时,真实流量 SLI 没有信号,需要合成监控(cuj-prober)7×24 主动拨测作为兜底。
- "监控对象多类目体系"纠正"什么都叫 CUJ":第一版调研把 71 个监控点全叫 CUJ(用户旅程),第二版纠正为 CUJ(14 个)+ Invariant(7 个系统不变量)+ SOP(7 个运维动作)+ 横向依赖(6 个)。不同类目用不同的可靠性范式:CUJ 走 SLO + 错误预算,Invariant 走零容忍立刻告警。
SLO 文档模板#
每个 SLO 必须有完整文档,不能只活在 PrometheusRule 里。模板:
# SLO: 订单服务可用性
## SLI 定义
- 指标名:order_api_availability
- 公式:sum(rate(http_requests_total{job="order-api", status!~"5.."}[5m])) / sum(rate(http_requests_total{job="order-api"}[5m]))
- 测量窗口:5m(实时) / 30d(SLO 评估)
## SLO 目标
- 月度可用性 ≥ 99.9%
- 等价于:每月允许 43 分钟"完全不可用",或更多时长的"部分降级"
## Owner
- 业务 Owner:交易服务部 张三
- SRE Owner:可靠性团队 李四
- 升级路径:SLO 违规 → SRE Owner → 业务 Owner → CTO
## 错误预算政策
- 预算 > 50%:正常发布
- 预算 25%-50%:发布前 review,禁止灰度 > 50%
- 预算 10%-25%:仅修复性发布,新功能冻结
- 预算 < 10%:完全冻结,全员投入修复
## SLA(如有)
- 对外承诺:99.5%(月度)
- 违约赔付:服务信用 10%
- 度量周期:自然月
## 历史数据
- 2026-04:实际 99.92%(达标)
- 2026-05:实际 99.85%(违规,触发复盘)
- 2026-06:实际 99.96%(达标)四、SLA 与赔付#
SLA 的法律属性#
SLA 不是内部目标,是对外承诺。通常包含:
- 服务可用性承诺(如 99.9%)
- 度量方法和统计周期(月度/季度)
- 未达标的赔付方式(服务信用额度、退款)
- 免责条款(计划内维护、不可抗力)
- 客户义务(合理使用、配合排查)
- 修改条款的通知期(通常 30-90 天)
SLA 设计要点#
- SLA 比 SLO 宽松。内部 SLO 99.95%,对外 SLA 99.9%,留缓冲。缓冲大小取决于业务风险偏好——金融类业务缓冲要大(一个九以上),创新业务可以小(半个九)。
- 信用额度而非现金赔付。绝大多数云厂商用服务 credit(服务信用),避免直接现金赔付带来的财务和法律复杂性。信用额度通常为月费的 10%-30%,按违约严重度递增。
- 明确排除项。计划内维护窗口、客户自身原因、第三方依赖故障、不可抗力等应明确排除。
- 连续多月未达标应有升级条款。允许客户无罚金解约。
- SLA 度量要有第三方可验证性。客户应该能独立验证 SLA 是否达标,不能只听厂商说。
主流云厂商 SLA 参考#
| 服务 | SLA | 违约赔付 |
|---|---|---|
| AWS EC2 | 99.99% 区域级 | 10%-30% 服务信用 |
| AWS S3 | 99.9% | 10%-25% |
| AWS RDS | 99.95% | 10%-25% |
| 阿里云 ECS | 99.95% | 服务信用 |
| Azure VM | 99.9% | 10%-25% |
| GCP Compute Engine | 99.99% 多实例 | 10%-50% |
注意:这些 SLA 通常有"分钟级不可用"才计入的门槛——5 分钟以下的抖动不算。这是云厂商的精算结果,也是 SRE 制定 SLA 时的参考。
五、从可观测性培养教材提取的能力地图#
可观测性培养教材将监控/可观测性能力分为 M1-M6 六层。SRE 可靠性工程在其中的位置:
| 模块 | 主题 | SRE 需要掌握什么 |
|---|---|---|
| M1 | 遥测信号 | 指标/日志/链路三信号的性质和成本特征,SLI 该用哪种信号计算 |
| M2 | 采集管道 | OpenTelemetry 标准埋点,保证 SLI 数据源可靠 |
| M3 | 存储查询 | PromQL 写 SLI 表达式和 Error Budget 计算 |
| M4 | 告警与 SRE | 核心重合区:SLI/SLO/Error Budget、症状告警、燃烧率告警 |
| M5 | 可视化方法论 | 黄金信号/RED/USE 框架指导 SLI 选取 |
| M6 | 架构与治理 | 多集群 SLO 聚合、配置即代码、成本控制 |
SRE 路线和可观测性培养教材的关系:可观测性教材讲"如何让系统可观测",SRE 路线讲"如何用可观测性做可靠性决策"。两者是上下游关系——可观测性是基础设施,SRE 是上层应用。
实战要点#
- SLI 从 2 个开始。第一个服务先选成功率和 P99 延迟两个 SLI,跑顺后再扩展。一开始就上 5 个 SLI 是常见的"过度设计"——团队还没消化就先被指标淹没。
- SLO 数字必须经业务方确认。不要 SRE 自己拍——业务方签字的 SLO 才有约束力。最好有邮件或会议纪要留底,将来争议时是依据。
- SLA 是法律文件,不要用口头约定替代。让法务或商务团队参与。SLA 一旦签了,修改成本极高(需要通知所有客户)。
- Prometheus Recording Rules 先行——参考 DevOps Ch25 部署 Prometheus 后,Recording Rules 是所有 SLO 计算的基础(见 DevOps Ch25 Prometheus 部署)。命名约定:
level:metric:operations,如job:http_requests:success_rate5m。 - 与 Error Budget 告警联动:SLO 定了之后,下一章讲怎么用 Error Budget 驱动告警和发布决策。
- SLO 是动态的,每季度回顾一次。业务变化、用户增长、架构演进都会让原 SLO 不再合适——该调就调,但每次调整都要有数据支撑和文档记录。
- SLO 不是越高越好。SLO 设过高的团队反而出更多事故——发布慢导致每次改动大。合适的 SLO 是"比用户期望略高一点",留出 budget 让工程师能折腾新东西。
- 多窗口 SLO 告警是 SLO 体系的标配。短窗口(5m/1h)+ 长窗口(6h/30d)AND 条件触发,避免抖动误报和长尾漏报。具体实现见 Ch08 告警工程。
小结#
SLI 是尺子(测量),SLO 是标尺的刻度(目标),SLA 是刻度加后果(违约赔付)。SRE 的核心工作就是用好这把尺子:选对 SLI、定准 SLO、用 Error Budget 守住 SLO。
一个团队是否真正建立了 SLO 体系,看三件事:有没有公开的 SLO Dashboard、有没有月度 SLO 回顾会、有没有因 SLO 违规触发的发布冻结。三件都做到就是真 SLO 体系;只做到其中一两件是"在建立中";一件都没做就是"挂着 SLO 名义的 dashboard 装饰"。
下一章展开 Error Budget——这把尺子怎么变成决策工具,把"可靠性"从口号变成可量化的工程约束。