你的系统上线了,可用性”挺高的”。具体多高?“反正没怎么出过事。”上个月有没有故障?“好像有一次,持续了几分钟,影响不大。”影响了多少用户?“不太清楚。”
这段对话在无数团队中反复出现。系统稳定性的管理停留在”感觉”层面——感觉还行,感觉没事,感觉问题不大。当产品经理要求加一个高风险的新功能时,工程师说”可能影响稳定性”,产品经理说”上次你也这么说,结果没事”。争论的双方都没有数据支撑。
Google 的 SRE(Site Reliability Engineering,站点可靠性工程)团队在 2003 年就开始面对这个问题。他们的解决方案不是”让系统更稳定”——因为无限稳定的成本是无限的——而是给稳定性一个精确的数字,然后围绕这个数字构建决策框架。
这个框架的核心是三个概念:SLI(Service Level Indicator,服务水平指标)、SLO(Service Level Objective,服务水平目标)和 SLA(Service Level Agreement,服务水平协议)。它们不是运维团队的内部指标,而是连接产品、工程、管理层的共同语言。
本文要回答三个问题:
- SLI / SLO / SLA 的精确定义是什么,它们之间的关系是什么?
- Error Budget(错误预算)如何把”稳定性 vs. 功能开发”从主观争论变成客量化决策?
- 怎么用多窗口燃烧率告警替代简单的阈值告警,减少告警噪声?
在上一篇中,我们讨论了容灾架构——如何在灾难发生时保障业务连续性。SLO 工程是容灾的另一面:不是应对极端事件,而是管理日常的可靠性水位。
一、SLI / SLO / SLA:从指标到契约
SLI:服务水平指标
SLI 是对系统行为的一个可量化的度量。它必须是具体的、可测量的、有业务含义的。
好的 SLI 的特征:
- 用户可感知。内部队列长度不是好的 SLI,但”请求延迟”是,因为用户能直接感受到。
- 可精确定义。“性能”不是 SLI,“第 99 百分位请求延迟”是。
- 有明确的计算公式。例如:可用性 SLI = 成功请求数 / 总请求数。
常见的 SLI 类型:
| SLI 类型 | 定义 | 适用场景 |
|---|---|---|
| 可用性(Availability) | 成功请求数 / 总请求数 | 几乎所有在线服务 |
| 延迟(Latency) | 请求处理时间的分布(通常取 p50、p99) | 面向用户的 API |
| 吞吐量(Throughput) | 单位时间处理的请求或事件数 | 数据管道、批处理系统 |
| 正确性(Correctness) | 返回正确结果的请求数 / 总请求数 | 搜索、推荐系统 |
| 新鲜度(Freshness) | 数据更新到可查询之间的延迟 | 数据仓库、搜索索引 |
| 持久性(Durability) | 成功存储的数据比例 | 存储系统 |
SLO:服务水平目标
SLO 是在 SLI 上设定的目标值。它表达的是:我们承诺这个 SLI 在某个时间窗口内达到某个水平。
例如:
- “过去 30 天内,API 可用性 >= 99.9%”。
- “过去 30 天内,API 第 99 百分位延迟 <= 300 毫秒”。
SLO 的关键特征:
- 有时间窗口。99.9% 的可用性是每天?每周?每月?每个选择的含义完全不同。
- 低于 100%。SLO 永远不应该是 100%,因为 100% 的可靠性是不可能的,追求 100% 意味着不允许任何变更,这会杀死产品迭代。
- 是内部目标,不是外部承诺。SLO 是工程团队给自己设定的标准。
SLA:服务水平协议
SLA 是与外部客户签订的法律契约。如果服务未达到 SLA 约定的水平,服务提供方需要承担后果(通常是经济赔偿)。
SLA 通常比 SLO 宽松。例如:
- SLO:99.95% 可用性。
- SLA:99.9% 可用性(未达标则赔偿月费的 10%)。
SLO 和 SLA 之间的差距是一个”安全边际”。如果 SLO 和 SLA 设为相同值,那么一旦 SLO 被突破,就立刻触发赔偿——没有任何缓冲。
三者的关系
graph LR
SLI["SLI<br/>指标:我们度量什么"] --> SLO["SLO<br/>目标:我们期望达到什么水平"]
SLO --> SLA["SLA<br/>契约:未达标的后果是什么"]
SLI --> |"成功请求/总请求"| M1["99.95%"]
M1 --> SLO
SLO --> |"安全边际"| SLA
SLA --> |"赔偿条款"| C["客户补偿"]
二、选择好的 SLI
选择 SLI 是 SLO 工程中最关键的一步。选错了 SLI,后面的所有工作都是在错误的方向上努力。
基于请求的 SLI vs. 基于窗口的 SLI
基于请求的 SLI(Request-based SLI):每个请求独立判断是”好”还是”坏”,然后计算好请求的比例。
可用性 SLI = 状态码非 5xx 的请求数 / 总请求数
适用于请求-响应模式的在线服务(HTTP API、gRPC 服务等)。
基于窗口的 SLI(Window-based SLI):把时间切分为固定长度的窗口(例如每分钟),每个窗口判断是”好”还是”坏”,然后计算好窗口的比例。
可用性 SLI = 数据同步延迟 < 5 秒的分钟数 / 总分钟数
适用于后台服务、数据管道等非请求-响应模式的系统。
SLI 的度量点
同一个 SLI,在不同位置度量,结果可能截然不同。
用户浏览器 → CDN → 负载均衡 → API 网关 → 应用服务 → 数据库
① ② ③ ④ ⑤ ⑥
在位置 ⑤ 度量的延迟可能是 20 毫秒,但用户在位置 ① 感受到的延迟可能是 200 毫秒(加上 DNS 解析、TCP 握手、TLS 协商、网络传输、前端渲染等)。
原则:SLI 应该尽可能靠近用户度量。 如果用户通过 HTTP API 访问服务,那么在负载均衡器或 API 网关处采集的请求日志是最佳的度量点——它既靠近用户端,又在你的控制范围内。
避免虚荣指标
以下指标看起来有用,但作为 SLI 容易误导:
- CPU 使用率。CPU 使用率 80% 不意味着用户体验差,CPU 使用率 20% 也不意味着用户体验好。它是容量指标,不是用户体验指标。
- 错误日志数量。错误日志可能包含大量无害的 warning,也可能遗漏了没被记录的真正错误。
- 平均延迟。平均值会掩盖长尾延迟。p50 = 10ms、p99 = 5000ms 的系统,平均延迟可能只有 50ms,但 1% 的用户等了 5 秒钟。
三、设定 SLO:不能太紧,不能太松
太紧的 SLO
如果 SLO 设为 99.999%(“五个九”),意味着每月只允许 26 秒的不可用时间。这意味着:
- 任何常规发布都可能消耗掉全部预算。
- 团队不敢做任何变更,产品迭代停滞。
- 告警噪声极大,工程师疲于奔命。
太松的 SLO
如果 SLO 设为 99%,意味着每月允许 7.2 小时的不可用时间。这意味着:
- 系统可以每个月宕机半天,用户已经忍无可忍了。
- Error Budget 永远用不完,SLO 形同虚设。
- 团队对可靠性没有任何约束力。
合理的 SLO 怎么定
- 从历史数据出发。过去 90 天,系统的实际可用性是多少?如果实际可用性是 99.95%,SLO 可以设为 99.9%——比实际稍低,留出合理的操作空间。
- 考虑用户期望。用户对延迟 200 毫秒和延迟 500 毫秒的感知差异很大,但对延迟 50 毫秒和延迟 100 毫秒的感知差异很小。SLO 应该反映用户真正关心的阈值。
- 考虑依赖方的 SLO。如果你的系统依赖一个 SLO 为 99.9% 的外部服务,你的系统的 SLO 不可能高于 99.9%(除非你有降级方案)。
- 逐步收紧。先从一个保守的 SLO 开始,积累数据后再逐步收紧。从 99.9% 收紧到 99.95% 远比从 99.99% 放松到 99.95% 容易被团队接受。
不同可用性等级的停机时间参考
| SLO 可用性 | 年度允许停机时间 | 月度允许停机时间 | 每日允许停机时间 |
|---|---|---|---|
| 99%(两个九) | 3.65 天 | 7.2 小时 | 14.4 分钟 |
| 99.9%(三个九) | 8.76 小时 | 43.8 分钟 | 1.44 分钟 |
| 99.95% | 4.38 小时 | 21.9 分钟 | 43.2 秒 |
| 99.99%(四个九) | 52.56 分钟 | 4.38 分钟 | 8.64 秒 |
| 99.999%(五个九) | 5.26 分钟 | 26.3 秒 | 0.86 秒 |
四、Error Budget:把稳定性变成可消费的资源
Error Budget(错误预算)是 Google SRE 最重要的概念之一。它的核心思想是:如果 SLO 不是 100%,那么 SLO 与 100% 之间的差距就是你”允许犯错”的空间。
计算方法
如果 SLO 是 99.9% 的可用性,每月的 Error Budget 是:
Error Budget = 1 - SLO = 1 - 99.9% = 0.1%
每月总请求数 = 1000 万
允许的失败请求数 = 1000 万 × 0.1% = 1 万
或者按时间计算:
每月总分钟数 = 30 × 24 × 60 = 43200 分钟
允许的不可用分钟数 = 43200 × 0.1% = 43.2 分钟
Error Budget 的消耗
Error Budget 像一个存款账户。每次故障都会从中”消费”一部分:
- 一次持续 10 分钟的服务中断,消耗了 10 / 43.2 = 23.1% 的月度 Error Budget。
- 一次影响 0.5% 请求的 Bug,在持续 2 小时期间消耗的 Error Budget = 0.5% × 2 小时 / 720 小时 = 0.0014%,占月度总预算的 1.4%。
Error Budget 策略
当 Error Budget 还有剩余时——团队可以:
- 正常发布新功能。
- 做架构实验(例如测试新的数据库引擎)。
- 进行混沌工程演练。
当 Error Budget 即将耗尽或已经耗尽时——团队必须:
- 冻结非关键功能的发布。
- 优先修复可靠性问题。
- 增加发布过程中的审核步骤(例如从自动部署退回到手动审批部署)。
- 开展事后复盘(Postmortem),找出根因并制定预防措施。
这就是 Error Budget 的仲裁价值。产品经理说”我要上新功能”,工程师说”系统不稳定不能上”——这个争论没有赢家,因为双方都在用主观判断。但如果引入 Error Budget:
- Budget 充足 → “数据显示我们有足够的 budget,可以上。”
- Budget 不足 → “数据显示 budget 已经不够了,必须先修稳定性。”
争论的对象从”人的判断”变成了”数据”,这是 SLO 工程最大的组织价值。
flowchart TD
A["每月 Error Budget 重置"] --> B{"当前 Budget 剩余"}
B -->|充足 > 50%| C["正常迭代<br/>功能发布、实验"]
B -->|告警 20%-50%| D["谨慎迭代<br/>增加发布审批<br/>优先修复已知问题"]
B -->|耗尽 < 20%| E["冻结功能发布<br/>全力修复可靠性<br/>事后复盘"]
C --> F["监控 Budget 消耗速率"]
D --> F
E --> G["恢复 Budget 后解冻"]
G --> F
F --> B
五、多窗口燃烧率告警
传统的可用性告警方式是设定一个固定阈值:如果过去 5 分钟的错误率超过 1%,就触发告警。这种方式有两个严重问题:
- 告警太多(高噪声)。短暂的错误率波动(比如一次网络抖动导致 5 秒内错误率飙升到 5%,然后立刻恢复)会频繁触发告警,工程师被告警疲劳淹没。
- 告警太慢(低灵敏度)。低速率的持续故障(比如错误率持续在 0.5%,远低于 1% 的阈值)可能不会触发告警,但如果持续一整天,消耗的 Error Budget = 0.5% × 24 小时 / 720 小时 ≈ 1.67%,30 天下来就消耗了 50%。
Google SRE Workbook 提出的解决方案是多窗口燃烧率告警(Multi-Window, Multi-Burn-Rate Alerting)。
燃烧率(Burn Rate)
燃烧率是 Error Budget 消耗速率的倍数。
燃烧率 = 实际错误率 / (1 - SLO)
如果 SLO = 99.9%(允许错误率 = 0.1%):
- 当前错误率 = 0.1% → 燃烧率 = 1x(正好按预算速度消耗)。
- 当前错误率 = 0.5% → 燃烧率 = 5x(以 5 倍速度消耗 budget,30 天的 budget 只够用 6 天)。
- 当前错误率 = 1.4% → 燃烧率 = 14x(30 天的 budget 只够用 2.14 天)。
多窗口策略
单一时间窗口的燃烧率告警仍然有问题:短窗口(5 分钟)容易误报,长窗口(1 小时)反应慢。解决方案是同时检查两个窗口:
- 长窗口:确认问题确实在持续,不是瞬时抖动。
- 短窗口:确认问题是当前正在发生的,不是窗口期内已经恢复的历史问题。
Google SRE Workbook 推荐的配置:
| 告警级别 | 长窗口 | 短窗口 | 燃烧率阈值 | Budget 消耗占比(如果持续) | 响应要求 |
|---|---|---|---|---|---|
| 紧急(Page) | 1 小时 | 5 分钟 | 14.4x | 2%(1 小时内) | 立即响应 |
| 紧急(Page) | 6 小时 | 30 分钟 | 6x | 5%(6 小时内) | 立即响应 |
| 工单(Ticket) | 3 天 | 6 小时 | 1x | 10%(3 天内) | 工作时间处理 |
Prometheus 实现
以下是基于 Prometheus 的多窗口燃烧率告警规则示例:
# 预聚合:计算不同时间窗口的错误率
groups:
- name: slo-error-rate
rules:
# 5 分钟窗口错误率
- record: slo:http_request_error_rate:5m
expr: |
sum(rate(http_requests_total{status=~"5.."}[5m]))
/
sum(rate(http_requests_total[5m]))
# 30 分钟窗口错误率
- record: slo:http_request_error_rate:30m
expr: |
sum(rate(http_requests_total{status=~"5.."}[30m]))
/
sum(rate(http_requests_total[30m]))
# 1 小时窗口错误率
- record: slo:http_request_error_rate:1h
expr: |
sum(rate(http_requests_total{status=~"5.."}[1h]))
/
sum(rate(http_requests_total[1h]))
# 6 小时窗口错误率
- record: slo:http_request_error_rate:6h
expr: |
sum(rate(http_requests_total{status=~"5.."}[6h]))
/
sum(rate(http_requests_total[6h]))
- name: slo-burn-rate-alerts
rules:
# 紧急告警:14.4x 燃烧率,1h/5m 双窗口
- alert: SLOBurnRateCritical
expr: |
slo:http_request_error_rate:1h > (14.4 * 0.001)
and
slo:http_request_error_rate:5m > (14.4 * 0.001)
labels:
severity: critical
annotations:
summary: "SLO burn rate critical: 14.4x"
description: "Error budget will be exhausted in less than 2 hours."
# 紧急告警:6x 燃烧率,6h/30m 双窗口
- alert: SLOBurnRateHigh
expr: |
slo:http_request_error_rate:6h > (6 * 0.001)
and
slo:http_request_error_rate:30m > (6 * 0.001)
labels:
severity: warning
annotations:
summary: "SLO burn rate high: 6x"
description: "Error budget will be exhausted in less than 5 days."Grafana Dashboard 设计
SLO Dashboard 需要回答三个核心问题:
- 当前状态:现在 SLO 达标吗?用一个大号的指示灯(绿/黄/红)。
- Budget 剩余:这个周期还剩多少 Error Budget?用一个进度条。
- 消耗趋势:按当前速度,Budget 会在什么时候耗尽?用一条趋势线。
┌─────────────────────────────────────────────────┐
│ API 可用性 SLO: 99.9% │
│ ┌───────┐ ┌──────────────────────┐ │
│ │ 🟢 │ │ Budget: 72% 剩余 │ │
│ │ 达标 │ │ ████████████░░░░░ │ │
│ └───────┘ └──────────────────────┘ │
│ │
│ 当前可用性: 99.94% | 月初至今 Error Budget 消耗: 28%│
│ ──────────────────────────────────────────── │
│ Budget 消耗趋势 │
│ 100%| ╱ │
│ | ╱ │
│ | ╱ │
│ | 当前消耗线 ────────╱ │
│ |───────────────── │
│ 0%|________________________________ 时间 │
│ 1日 10日 20日 30日 │
└─────────────────────────────────────────────────┘
六、SLO 作为架构决策的仲裁者
SLO 不仅仅是告警的依据。在架构决策中,SLO 提供了一个客观的判断框架。
场景一:要不要引入缓存层
“缓存能提升性能”是一个模糊的理由。用 SLO 来分析:
- 当前 p99 延迟 SLI = 800 毫秒,SLO 目标 = 500 毫秒。
- 引入缓存后,缓存命中时 p99 延迟 = 50 毫秒,缓存未命中时 p99 延迟 = 850 毫秒(多了一次缓存查询的开销)。
- 预计缓存命中率 = 85%。
- 预计 p99 延迟 = 0.85 × 50 + 0.15 × 850 = 170 毫秒。满足 500 毫秒的 SLO。
但缓存引入了新的故障模式:缓存集群不可用时,所有请求穿透到数据库,可能导致数据库过载。需要评估这个故障模式对可用性 SLO 的影响。
场景二:要不要做服务拆分
一个单体服务的可用性是 99.95%。如果拆分成 3 个串行调用的微服务,假设每个微服务的可用性也是 99.95%:
串联系统可用性 = 99.95% × 99.95% × 99.95% = 99.85%
可用性从 99.95% 下降到 99.85%,月度停机时间从 21.9 分钟增加到 65.7 分钟。如果 SLO 是 99.9%,这个拆分方案直接导致 SLO 无法达标。
这不意味着不能拆分,但意味着拆分后必须通过其他手段(重试、熔断、降级)来补偿可用性损失。SLO 让这个权衡变得可量化。
场景三:数据库选型
在选择数据库时,不同产品的可靠性特征不同:
- 选项 A:云厂商托管数据库,SLA 99.95%,延迟 p99 = 5 毫秒。
- 选项 B:自建数据库集群,预估可用性 99.9%,延迟 p99 = 2 毫秒。
如果服务的 SLO 是 99.95% 可用性,选项 B 的 99.9% 可用性已经低于服务 SLO,仅数据库一个组件就可能耗尽全部 Error Budget。选项 A 虽然延迟稍高,但可用性更有保障。
七、SLO 驱动的组织行为
SLO 的影响不仅限于技术层面,它改变了组织的行为模式。
产品 vs. 工程的冲突仲裁
最常见的冲突是:产品团队想快速发布新功能,工程团队想花时间修复技术债务和提升稳定性。
没有 SLO 时,这个冲突的解决方式通常是:谁的职级高听谁的,或者谁声音大听谁的。结果是要么稳定性被牺牲(系统频繁出故障),要么迭代速度被牺牲(团队变得过度保守)。
有 SLO 和 Error Budget 后,规则变成:
- Error Budget 充足 → 产品优先。工程团队不能以”稳定性风险”为由阻止功能发布——数据证明我们有足够的犯错空间。
- Error Budget 不足 → 稳定性优先。产品团队不能要求”赶紧上线”——数据证明我们已经没有犯错空间了。
这个机制的关键是双方在事前就同意了规则。Error Budget 策略应该以书面文件的形式存在,由产品负责人和工程负责人共同签字。
发布节奏的量化管理
SLO 和 Error Budget 还可以用来量化发布的”安全余量”。
假设每次发布平均消耗 2% 的月度 Error Budget(来自灰度发布期间的少量错误)。如果月度 Error Budget 总量是 43.2 分钟,那么每次发布平均消耗 0.864 分钟。一个月最多可以做 43.2 / 0.864 ≈ 50 次发布。
如果团队想增加发布频率(比如从每周发布改为每日发布),就需要降低每次发布消耗的 Error Budget——这意味着需要投资更好的灰度发布机制、更完善的自动化回滚、更细粒度的特性开关(Feature Flag)。
事后复盘的量化标准
什么事故值得做事后复盘(Postmortem)?一个实用的标准是:消耗了超过 N% 月度 Error Budget 的事故。
例如:
- 消耗 > 20% Budget → P1 事故,必须做 Postmortem,48 小时内完成。
- 消耗 5-20% Budget → P2 事故,建议做 Postmortem,一周内完成。
- 消耗 < 5% Budget → P3 事故,记录即可,不强制 Postmortem。
这比传统的”影响了 X 个用户”或”持续了 X 分钟”的分类标准更有意义,因为 Error Budget 已经综合考虑了影响范围和持续时间。
八、工程案例:某电商平台的 SLO 落地实践
以下案例来自国内某中型电商平台的公开技术分享,展示了从”没有 SLO”到”SLO 驱动”的转变过程。
背景
- 团队规模:约 80 名工程师,15 个微服务。
- 业务规模:日活用户约 200 万,日均订单约 30 万笔。
- 痛点:每次大促后都有大量故障复盘,但复盘结论难以落地;产品和工程团队之间关于”先上功能还是先修 Bug”的争论持续不断。
第一步:选择 SLI(第 1-2 周)
团队识别出 3 个核心用户旅程(User Journey):
- 商品浏览:用户搜索商品 → 查看商品详情。
- 下单支付:加入购物车 → 提交订单 → 完成支付。
- 物流查询:查看订单状态 → 查看物流信息。
为每个旅程选择了 SLI:
| 用户旅程 | SLI:可用性 | SLI:延迟 |
|---|---|---|
| 商品浏览 | 搜索 API 成功率 | 搜索 API p99 延迟 |
| 下单支付 | 下单 API 成功率 | 下单 API p99 延迟 |
| 物流查询 | 物流 API 成功率 | 物流 API p99 延迟 |
度量点选择在 API 网关层(Nginx 访问日志),因为这是距离用户最近的可控度量点。
第二步:设定 SLO(第 3-4 周)
基于过去 90 天的历史数据:
| SLI | 历史实际水平 | 设定的 SLO |
|---|---|---|
| 搜索 API 成功率 | 99.95% | 99.9% |
| 搜索 API p99 延迟 | 420 毫秒 | 500 毫秒 |
| 下单 API 成功率 | 99.92% | 99.9% |
| 下单 API p99 延迟 | 850 毫秒 | 1000 毫秒 |
| 物流 API 成功率 | 99.97% | 99.9% |
| 物流 API p99 延迟 | 200 毫秒 | 300 毫秒 |
SLO 设定略低于历史水平,给发布和实验留出 Error Budget。
第三步:建设可观测性(第 5-8 周)
- 部署 Prometheus 采集 Nginx 日志中的请求状态和延迟。
- 使用 Prometheus Recording Rules 预计算各 SLI 的窗口聚合值。
- 搭建 Grafana SLO Dashboard,包含 SLI 实时值、Error Budget 剩余百分比、燃烧率趋势。
- 配置多窗口燃烧率告警,接入 PagerDuty 和企业微信。
第四步:制定 Error Budget 策略(第 9-10 周)
产品总监和技术总监共同签署了 Error Budget 策略文件:
- 每月 1 日重置 Error Budget。
- Budget > 50%:正常迭代,每周发布。
- Budget 20%-50%:增加发布前的 Staging 环境验证步骤,取消”紧急发布”通道。
- Budget < 20%:冻结功能发布,全力修复可靠性问题,直到 Budget 恢复到 30% 以上。
- 大促期间(双十一前后两周):冻结所有非关键变更。
效果
运行 6 个月后的数据:
- 月均 P1 故障从 3.2 次降到 1.1 次。
- 产品与工程团队的争执减少——“Error Budget 说了算”成为共识。
- 发布频率从每周 1 次增加到每周 3 次(因为每次发布的 Budget 消耗降低了,得益于更完善的灰度发布机制)。
- 工程师对告警的响应速度提升——因为告警噪声减少了 70%,每一条告警都是有意义的。
九、SLO 的常见误区
误区一:SLO 越高越好
99.99% 听起来比 99.9% “好”,但它意味着 10 倍的成本和 10 倍的运维压力。大多数业务不需要四个九。一个内部管理系统的 SLO 设为 99.99% 是资源浪费。
误区二:SLO = SLA
SLO 是内部目标,SLA 是外部承诺。它们的受众、后果和设定逻辑完全不同。把 SLO 和 SLA 设为同一个值,意味着你没有安全边际——SLO 刚被突破就要赔钱。
误区三:只关注可用性
很多团队只设了可用性 SLO,忽略了延迟 SLO。一个可用性 99.99% 但 p99 延迟 10 秒的系统,用户体验并不好。可用性和延迟应该成对出现。
误区四:SLO 定了就不改
SLO 应该是一个活文档(Living Document)。业务变化了(用户量翻倍)、架构变化了(从单体拆成微服务)、用户期望变化了——SLO 都需要相应调整。建议每季度 Review 一次 SLO 的合理性。
误区五:忽视依赖链
你的服务依赖数据库、缓存、消息队列、第三方 API。每个依赖都有自己的可靠性上限。如果你的数据库 SLA 是 99.95%,你的服务 SLO 就不可能比 99.95% 更高(除非你有完善的降级方案)。设定 SLO 时,必须考虑整个依赖链的可靠性。
十、SLO 工程的权衡
| 维度 | 没有 SLO | SLO 过于宽松 | SLO 合理 | SLO 过于严格 |
|---|---|---|---|---|
| 稳定性管理 | 靠感觉 | 形同虚设 | 数据驱动 | 过度保守 |
| 产品迭代速度 | 不可预测 | 无约束 | 有节奏 | 接近停滞 |
| 告警噪声 | 高(随意设阈值) | 低(几乎不告警) | 低(有意义的告警) | 极高(频繁告警) |
| 工程师体验 | 疲于救火 | 缺乏挑战 | 专注 | 疲于奔命 |
| 故障复盘 | 凭感觉分级 | 缺乏标准 | Budget 驱动的分级 | 过度复盘 |
| 成本 | 低(无额外投入) | 低 | 中(可观测性投入) | 高(冗余和容灾投入) |
| 组织信任 | 低 | 低 | 高 | 中(团队压力大) |
| 适用阶段 | 早期探索 | 不推荐 | 成长期和成熟期 | 极端关键系统 |
十一、结论
SLO 工程的核心不是设定一个数字,而是围绕这个数字建立一套决策机制:
- 选择正确的 SLI——度量用户真正关心的指标,在靠近用户的位置度量。
- 设定合理的 SLO——不太紧(杀死迭代),不太松(形同虚设),基于历史数据和业务需求。
- 实施 Error Budget 策略——把”稳定性 vs. 功能开发”从主观争论变成量化决策。
- 建设多窗口燃烧率告警——减少告警噪声,提高告警质量。
- 让 SLO 驱动架构决策——缓存要不要加、服务要不要拆、数据库怎么选——都可以用 SLO 来量化评估。
SLO 不是银弹。它不能阻止故障发生,也不能自动修复 Bug。但它提供了一个共同语言,让产品、工程、管理层在”可靠性应该是多少”这个问题上达成共识。在大多数团队中,这个共识的价值远大于任何单一技术改进。
导航
上一篇:容灾架构:多活与灾备设计
下一篇:容量规划:从拍脑袋到数据驱动
参考资料
书籍
- Betsy Beyer, Chris Jones, Jennifer Petoff, Niall Richard Murphy, “Site Reliability Engineering: How Google Runs Production Systems”, O’Reilly, 2016. SRE 的开创性著作,第四章详细论述了 SLI/SLO/SLA 的定义和实践。
- Betsy Beyer, Niall Richard Murphy, David K. Rensin, Kent Kawahara, Stephen Thorne, “The Site Reliability Workbook”, O’Reilly, 2018. 第二章和第五章给出了多窗口燃烧率告警的完整推导。
- Alex Hidalgo, “Implementing Service Level Objectives”, O’Reilly, 2020. 目前关于 SLO 实施最完整的专著。
论文与博客
- Google Cloud Blog, “SRE fundamentals: SLIs, SLAs and SLOs”, 2018. SLI/SLO/SLA 关系的简明解释。
- Google Cloud Blog, “Alerting on SLOs like Pros”, 2020. 多窗口燃烧率告警的工程实践细节。
- Will Larson, “Setting SLOs”, Irrational Exuberance Blog, 2021. 关于如何在工程组织中推动 SLO 采纳的实操建议。
工具
- Prometheus 官方文档, “Recording Rules”. 预聚合规则的详细语法和最佳实践。
- Grafana Labs, “SLO Monitoring and Alerting with Grafana”, 2022. 基于 Grafana 的 SLO Dashboard 模板和告警配置指南。
- Sloth: GitHub 仓库(slok/sloth),基于 Prometheus 的 SLO 生成工具,自动生成燃烧率告警规则。
- OpenSLO: GitHub 仓库(openslo/openslo),SLO 定义的开放标准,支持多种可观测性后端。
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【系统架构设计百科】告警策略:如何避免"狼来了"
大多数团队的告警系统都在制造噪声而不是传递信号。阈值告警看似直观,实则产生大量误报和漏报,值班工程师在凌晨三点被叫醒,却发现只是一次无害的毛刺。本文从告警疲劳的工业数据出发,拆解基于 SLO 的多窗口燃烧率告警算法,深入 Alertmanager 的路由、抑制与分组机制,结合 PagerDuty 的告警疲劳研究和真实工程案例,给出一套可落地的告警策略设计方法。
【系统架构设计百科】故障排查方法论:从告警到根因的系统化路径
凌晨三点的告警响了,你打开笔记本,盯着一堆指标不知道从哪里下手——两小时后发现是配置改错了。这种经历几乎每个 oncall 工程师都有过。本文从 Incident Command System 在 SRE 中的适配讲起,拆解从告警到根因的系统化排查路径,覆盖事件分级、假设驱动调试、事后复盘的无责文化、Google 与 Meta 的 oncall 体系,给出可落地的 Runbook 模板和 Postmortem 模板。
【系统架构设计百科】架构质量属性:不只是"高可用高性能"
需求评审时写下的'高可用、高性能、高并发',到了架构设计阶段几乎无法落地——因为它们不是可执行的需求。本文从 SEI/CMU 的质量属性理论出发,用 stimulus-response 场景模型把模糊需求变成可量化、可验证的架构约束,并拆解属性之间的冲突与联动关系。
【系统架构设计百科】复杂性管理:架构的核心战场
系统复杂性是架构腐化的根源——本文从 Brooks 的本质复杂性与偶然复杂性划分出发,结合认知负荷理论与 Parnas 的信息隐藏原则,系统阐述复杂性的来源、度量与控制手段,并给出可操作的架构策略