「如果没有量化的可靠性目标,你就无法判断一次发布是『太激进』还是『太保守』。」 — Google SRE Book
SLO(Service Level Objective)是 SRE 文化的基石。它将模糊的"系统要稳定"转化为精确的"99.9% 的请求必须在 200ms 内返回",进而推导出错误预算——告诉你这个月还能承受多少停机时间。
一、核心概念
1.1 术语金字塔
┌─────────┐
│ SLA │ ← 面向客户的合同承诺(法律约束)
│ 99.95% │ 违约有赔偿
└────┬────┘
│ 基于
┌────▼────┐
│ SLO │ ← 内部目标(略高于 SLA)
│ 99.98% │ 团队努力的方向
└────┬────┘
│ 基于
┌────▼────┐
│ SLI │ ← 量化指标(原始数据)
│ 可用性 │ 可测量的东西
└─────────┘
关键区别:
SLA = 对客户的承诺(做到 99.9%)
SLO = 内部目标(努力做到 99.95%)
SLI = 测量指标(实际测量值)
错误预算 = 1 - SLO
例:SLO = 99.9% → 错误预算 = 0.1% = 43.8 分钟/月
1.2 SLI 选取方法论
SLI 选取原则:
1. 用户关心什么?不是"CPU 使用率",而是"页面加载速度"
2. 可测量?有数据源能持续采集
3. 可控制?团队能影响这个指标
SLI 常见类型:
├── Availability(可用性)— 请求是否成功?
├── Latency(延迟) — 多快返回?
├── Quality(质量) — 返回的内容是否正确?
├── Error Rate(错误率) — 多少比例失败?
└── Throughput(吞吐) — 处理多少请求?
反模式:
❌ CPU 使用率作为 SLI(用户不关心)
❌ 测试覆盖率作为 SLI(不是用户体验)
❌ 部署频率作为 SLI(是过程指标,非结果指标)
1.3 SLI 定义示例
| 服务 | SLI 类型 | 定义 | 测量方式 |
|---|---|---|---|
| Web API | 可用性 | 成功 HTTP 请求比例 | 1 - (5xx / 总请求) |
| Web API | 延迟 | P99 响应时间 | histogram_quantile(0.99) |
| 搜索 | 质量 | 搜索结果相关性得分 | 人工标注 + ML 模型 |
| 视频流 | 质量 | 播放过程中不卡顿比例 | 前端事件上报 |
| 消息队列 | 延迟 | 消息从发布到消费的 P99 | 消息时间戳差值 |
二、SLO 目标设定
2.1 目标值选择
SLO 不是越高越好:
├── 99.9% = 43.8 分钟/月 停机预算
├── 99.95% = 21.9 分钟/月
├── 99.99% = 4.38 分钟/月 ← 成本剧增
└── 99.999% = 26.3 秒/月 ← 多数公司不需要
成本分析:
从 99.9% → 99.99%,可靠性提升 10 倍
但成本可能提升 50-100 倍
→ 除非业务需要,否则不要过度工程化
设定原则:
- 从当前水平出发,设定有挑战但可达的目标
- 比 SLA 稍高(留出缓冲)
- 少而精:每个服务 2-3 个核心 SLO
2.2 SLO 模板
# slo.yml
service: payment-api
version: 1.0
slos:
- name: availability
display_name: "Payment API Availability"
description: "Successful requests ratio"
sli:
type: availability
expression: |
sum(rate(http_requests_total{job="payment-api",status!~"5.."}[window])) /
sum(rate(http_requests_total{job="payment-api"}[window]))
target: 0.9995 # 99.95%
window: 30d
alerting:
burn_rate_alerts:
fast_burn: { multiplier: 14, window: 1h }
slow_burn: { multiplier: 2, window: 6h }
- name: latency
display_name: "Payment API Latency"
description: "P99 latency for successful requests"
sli:
type: latency
expression: |
histogram_quantile(0.99,
sum(rate(http_request_duration_seconds_bucket{job="payment-api"}[window]))
)
target: 0.2 # 200ms
window: 30d
三、错误预算
3.1 计算
错误预算 = 允许的不可用/不满足请求数
Example:
SLO: 99.9% 可用性
月度请求总数: 1,000,000,000
错误预算 = 1,000,000,000 × 0.001 = 1,000,000 请求
时间等价:
30天 = 30 × 24 × 60 = 43,200 分钟
99.9% → 错误预算 = 43.2 分钟/月
99.99% → 错误预算 = 4.32 分钟/月
3.2 错误预算消费监控
# 30 天错误预算消费率
(
sum(rate(http_requests_total{status=~"5.."}[30d])) /
sum(rate(http_requests_total[30d]))
) / (1 - 0.999) # 除以错误预算比例
# 结果解读:
# < 1 → 预算健康,有余量
# = 1 → 刚好用完预算
# > 1 → 预算已超支,停止非必要变更
四、Burn Rate 告警
4.1 核心思想
Burn Rate = 当前错误率 / SLO 错误预算比率
例:
SLO = 99.9% → 错误预算比率 = 0.1%
当前错误率 = 1%
Burn Rate = 1% / 0.1% = 10x
含义:以当前速度,10 天内就会耗尽月度错误预算。
Google SRE 推荐双窗口多 Burn Rate:
├── 快速燃尽(Fast Burn):Burn Rate ≥ 14.4x
│ └── 在 2 天内耗尽预算 → 立即通知 P0
│ └── 检测窗口:1h(长窗口)+ 5min(短窗口)
│
└── 慢速燃尽(Slow Burn):Burn Rate ≥ 2x
└── 在 15 天内耗尽预算 → 通知 P1
└── 检测窗口:6h(长窗口)+ 30min(短窗口)
4.2 Prometheus Burn Rate 告警
# burn_rate_alerts.yml
groups:
- name: burn_rate_fast
interval: 30s
rules:
# 快速燃尽:1h 窗口内 Burn Rate >= 14.4
- alert: ErrorBudgetBurnFast
expr: |
(
sum(rate(http_requests_total{status=~"5.."}[1h]))
/
sum(rate(http_requests_total[1h]))
) / (1 - 0.999) > 14.4
and
(
sum(rate(http_requests_total{status=~"5.."}[5m]))
/
sum(rate(http_requests_total[5m]))
) / (1 - 0.999) > 14.4
for: 2m
labels:
severity: p0
annotations:
summary: "Fast error budget burn detected"
description: "Error rate is {{ $value | humanizePercentage }}x over budget"
- name: burn_rate_slow
interval: 30s
rules:
# 慢速燃尽:6h 窗口内 Burn Rate >= 2
- alert: ErrorBudgetBurnSlow
expr: |
(
sum(rate(http_requests_total{status=~"5.."}[6h]))
/
sum(rate(http_requests_total[6h]))
) / (1 - 0.999) > 2
and
(
sum(rate(http_requests_total{status=~"5.."}[30m]))
/
sum(rate(http_requests_total[30m]))
) / (1 - 0.999) > 2
for: 1h
labels:
severity: p1
annotations:
summary: "Slow error budget burn detected"
五、基于错误预算的发布策略
5.1 发布窗口
错误预算充足 (> 50%):
✅ 正常发布
✅ 可以尝试新技术
✅ 可以关闭部分冗余监控节省成本
错误预算紧张 (10-50%):
⚠️ 增加 Canary 比例和观察时间
⚠️ 非紧急功能延后
⚠️ 增加发布审批流程
错误预算耗尽 (< 10%):
❌ 禁止非必要发布
❌ 只接受 P0 修复
❌ 需要 VP 审批才能发布
❌ 团队 focus 转移到稳定性修复
5.2 发布看板
月度错误预算看板:
Payment Service
SLO: 99.9% | 预算: 43.2 分钟
┌──────────────────────────────┐
│ ████████████████████░░░░░░░░ │ 已用: 68% (29.4 分钟)
│ 绿色=健康 黄色=谨慎 红色=停止发布 │
└──────────────────────────────┘
本月剩余预算: 13.8 分钟
当前状态: 🟡 谨慎发布
Search Service
SLO: 99.95% | 预算: 21.9 分钟
┌──────────────────────────────┐
│ █████░░░░░░░░░░░░░░░░░░░░░░░ │ 已用: 15% (3.3 分钟)
└──────────────────────────────┘
本月剩余预算: 18.6 分钟
当前状态: 🟢 正常发布
六、SLO 面板设计
// Grafana Dashboard JSON(关键面板)
{
"title": "SLO Status",
"panels": [
{
"title": "Availability (30d)",
"type": "stat",
"targets": [{
"expr": |
sum(rate(http_requests_total{job=~"$service",status!~"5.."}[30d])) /
sum(rate(http_requests_total{job=~"$service"}[30d]))
}],
"fieldConfig": {
"defaults": {
"unit": "percentunit",
"thresholds": {
"steps": [
{ "color": "red", "value": 0 },
{ "color": "yellow", "value": 0.999 },
{ "color": "green", "value": 0.9995 }
]
}
}
}
},
{
"title": "Error Budget Remaining",
"type": "bargauge",
"targets": [{
"expr": |
1 - (
sum(rate(http_requests_total{job=~"$service",status=~"5.."}[30d])) /
sum(rate(http_requests_total{job=~"$service"}[30d]))
) / (1 - 0.999)
}],
"fieldConfig": {
"defaults": {
"unit": "percentunit",
"min": 0,
"max": 1
}
}
},
{
"title": "Burn Rate",
"type": "timeseries",
"targets": [
{
"expr": |
(sum(rate(http_requests_total{job=~"$service",status=~"5.."}[1h])) /
sum(rate(http_requests_total{job=~"$service"}[1h]))) / (1 - 0.999),
"legendFormat": "1h burn rate"
}
]
}
]
}
七、SLO 文化与治理
7.1 实施路线图
Phase 1: 试点(1-2 个月)
├── 选 1-2 个核心服务
├── 定义 SLI + SLO
├── 建立错误预算看板
└── 团队培训
Phase 2: 推广(3-6 个月)
├── 扩展到所有关键服务
├── 建立 Burn Rate 告警
├── 错误预算纳入发布流程
└── 定义发布冻结策略
Phase 3: 成熟(6+ 个月)
├── SLO 纳入团队 OKR
├── 自动化错误预算管理
├── 与财务挂钩(过度可靠性成本)
└── 年度 SLO 评审与调整
7.2 常见陷阱
| 陷阱 | 表现 | 解决 |
|---|---|---|
| SLO 太多 | 每个服务 10 个 SLO | 限制 2-3 个核心 |
| SLO 太松 | 100% 时间达标 | 有挑战性的目标 |
| SLO 不可测 | 没有数据源 | 确保可自动化测量 |
| 忽视用户体验 | 后端 99.99% 但前端很卡 | SLI 从用户视角定义 |
| 从不调整 | 设定后一年不变 | 季度评审 |
参考与延伸阅读
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。