引言
服务等级目标(Service Level Objectives,SLO)是Google SRE实践的核心概念。SLO帮助我们量化系统可靠性,平衡创新速度与稳定性,建立与用户的信任关系。
核心概念
SLO vs SLI vs SLA
SLI(Service Level Indicator):服务等级指标
- 实际测量的指标
- 例如:成功率、延迟P99
SLO(Service Level Objective):服务等级目标
- 基于SLI设定的目标
- 例如:99.9%的请求在200ms内成功响应
SLA(Service Level Agreement):服务等级协议
- 与用户的商业合同
- 违反SLA需要赔偿
- 通常比SLO更宽松
关系图
用户期望
↓
SLA(商业承诺,如99.5%)
↓
SLO(内部目标,如99.9%)
↓
SLI(实际测量,如99.95%)
定义有效的SLI
请求/响应型服务
# 可用性SLI
availability_sli:
description: "成功请求占比"
formula: |
(total_requests - failed_requests) / total_requests
# Prometheus查询
query: |
(
sum(rate(http_requests_total{status!~"5.."}[5m]))
/
sum(rate(http_requests_total[5m]))
)
target: 99.9%
# 延迟SLI
latency_sli:
description: "P99延迟低于200ms的请求占比"
formula: |
requests_with_latency < 200ms / total_requests
query: |
(
sum(rate(http_request_duration_seconds_bucket{le="0.2"}[5m]))
/
sum(rate(http_request_duration_seconds_count[5m]))
)
target: 99%
# 吞吐量SLI
throughput_sli:
description: "系统能够处理预期负载"
query: |
sum(rate(http_requests_total[5m])) > 1000 # 至少1000 QPS
数据处理型服务
# 数据新鲜度SLI
freshness_sli:
description: "数据处理延迟"
formula: |
(now - last_successful_process_time)
# 监控最新成功处理时间
metric: batch_job_last_success_timestamp_seconds
target: "< 5分钟"
# 数据完整性SLI
completeness_sli:
description: "成功处理的数据占比"
formula: |
processed_records / expected_records
query: |
(
sum(batch_records_processed_total)
/
sum(batch_records_expected_total)
)
target: 99.99%
# 覆盖率SLI(存储系统)
coverage_sli:
description: "成功响应的读取请求占比"
query: |
(
sum(rate(storage_reads_total{status="success"}[5m]))
/
sum(rate(storage_reads_total[5m]))
)
target: 99.999%
制定合理的SLO
SLO制定框架
## SLO制定清单
### 1. 识别关键用户旅程
- [ ] 用户登录/认证
- [ ] 核心业务操作(如创建订单)
- [ ] 数据查询/读取
- [ ] 数据写入/更新
### 2. 为每个旅程定义SLI
- [ ] 可用性(成功率)
- [ ] 延迟(P50、P95、P99)
- [ ] 吞吐量
- [ ] 数据质量(新鲜度、完整性)
### 3. 设定目标值
考虑因素:
- [ ] 用户容忍度(通过调研)
- [ ] 技术可行性
- [ ] 业务影响
- [ ] 竞争对手水平
- [ ] 历史表现
### 4. 确定测量窗口
- [ ] 滑动窗口(如30天)
- [ ] 日历年(如月度)
- [ ] 基于业务周期(如季度)
常见SLO目标参考
slo_benchmarks:
# 面向用户的核心API
user_facing_api:
availability: 99.9% # 每月43分钟宕机
latency_p99: 99% < 200ms
latency_p50: 99% < 50ms
# 内部服务
internal_service:
availability: 99.95% # 每月22分钟宕机
latency_p99: 99% < 500ms
# 批处理作业
batch_processing:
success_rate: 99.99%
freshness: 99% < 15分钟
# 数据存储
data_storage:
availability: 99.999% # 每月26秒宕机
durability: 99.999999999% # 11个9
# CDN/静态资源
static_content:
availability: 99.99%
latency_p95: 99% < 100ms
cache_hit_rate: > 95%
错误预算管理
错误预算计算
class ErrorBudgetCalculator:
def __init__(self, slo_target: float, window_days: int = 30):
self.slo_target = slo_target
self.window_seconds = window_days * 24 * 3600
def calculate_budget(self, total_requests: int) -> int:
"""计算错误预算(允许失败的请求数)"""
return int(total_requests * (1 - self.slo_target))
def calculate_budget_remaining(self,
total_requests: int,
failed_requests: int) -> float:
"""计算剩余错误预算百分比"""
budget = self.calculate_budget(total_requests)
remaining = budget - failed_requests
return (remaining / budget) * 100
def budget_burn_rate(self,
total_requests: int,
failed_requests: int,
elapsed_seconds: int) -> float:
"""计算错误预算消耗速率(倍数)"""
expected_failures = total_requests * (1 - self.slo_target)
actual_rate = failed_requests / elapsed_seconds
expected_rate = expected_failures / self.window_seconds
return actual_rate / expected_rate
# 使用示例
calculator = ErrorBudgetCalculator(slo_target=0.999, window_days=30)
# 假设30天内处理了1000万次请求
total_requests = 10_000_000
failed_requests = 5_000
budget = calculator.calculate_budget(total_requests)
print(f"错误预算: {budget} 次失败") # 10,000次
remaining = calculator.calculate_budget_remaining(
total_requests, failed_requests
)
print(f"剩余预算: {remaining:.1f}%") # 50%
# 如果前10天就消耗了50%预算
burn_rate = calculator.budget_burn_rate(
total_requests // 3, # 10天的请求量
5_000, # 已失败数
10 * 24 * 3600 # 10天秒数
)
print(f"消耗速率: {burn_rate:.1f}x") # 1.5x(消耗太快)
多窗口告警策略
# Prometheus告警规则
groups:
- name: slo_alerts
rules:
# 快速燃烧告警(1小时窗口,14.4x燃烧速率)
# 会在1小时内消耗14.4%的30天预算
- alert: SLOBudgetBurnFast
expr: |
(
# 短期窗口(1小时)
(
sum(rate(http_requests_total{status=~"5.."}[1h]))
/
sum(rate(http_requests_total[1h]))
) > (14.4 * 0.001)
)
and
(
# 长期窗口(6小时)确认趋势
(
sum(rate(http_requests_total{status=~"5.."}[6h]))
/
sum(rate(http_requests_total[6h]))
) > (6 * 0.001)
)
for: 5m
labels:
severity: critical
slo: api_availability
annotations:
summary: "SLO错误预算快速消耗"
description: "1小时窗口内错误率达到SLO的14.4倍"
runbook: "https://wiki.example.com/runbooks/slo-burn-fast"
# 中等燃烧告警(6小时窗口,6x燃烧速率)
- alert: SLOBudgetBurnMedium
expr: |
(
sum(rate(http_requests_total{status=~"5.."}[6h]))
/
sum(rate(http_requests_total[6h]))
) > (6 * 0.001)
and
(
sum(rate(http_requests_total{status=~"5.."}[24h]))
/
sum(rate(http_requests_total[24h]))
) > (3 * 0.001)
for: 30m
labels:
severity: warning
slo: api_availability
annotations:
summary: "SLO错误预算中等速度消耗"
# 慢速燃烧告警(3天窗口,持续高错误率)
- alert: SLOBudgetBurnSlow
expr: |
(
sum(rate(http_requests_total{status=~"5.."}[3d]))
/
sum(rate(http_requests_total[3d]))
) > 0.001
for: 2h
labels:
severity: info
slo: api_availability
annotations:
summary: "SLO错误预算缓慢消耗"
Grafana SLO仪表板
{
"dashboard": {
"title": "SLO监控仪表板",
"panels": [
{
"title": "当前SLO达成率",
"type": "stat",
"targets": [
{
"expr": "slo_availability_ratio",
"legendFormat": "可用性"
}
],
"thresholds": [
{ "value": 0.999, "color": "green" },
{ "value": 0.995, "color": "yellow" },
{ "value": 0, "color": "red" }
]
},
{
"title": "错误预算剩余",
"type": "gauge",
"targets": [
{
"expr": "slo_error_budget_remaining_percent",
"legendFormat": "剩余预算%"
}
],
"max": 100,
"thresholds": [
{ "value": 50, "color": "green" },
{ "value": 20, "color": "yellow" },
{ "value": 0, "color": "red" }
]
},
{
"title": "错误预算消耗趋势(30天)",
"type": "graph",
"targets": [
{
"expr": "slo_error_budget_burned_over_time",
"legendFormat": "已消耗预算"
},
{
"expr": "slo_error_budget_expected_burn",
"legendFormat": "预期消耗(线性)"
}
]
},
{
"title": "燃烧速率(多窗口)",
"type": "table",
"targets": [
{
"expr": "slo_burn_rate_1h",
"legendFormat": "1小时"
},
{
"expr": "slo_burn_rate_6h",
"legendFormat": "6小时"
},
{
"expr": "slo_burn_rate_1d",
"legendFormat": "1天"
},
{
"expr": "slo_burn_rate_3d",
"legendFormat": "3天"
}
]
}
]
}
}
SLO实施流程
故障响应流程
## SLO告警响应SOP
### 1. 告警触发(燃烧速率 > 14.4x)
- [ ] 确认告警真实性(排除误报)
- [ ] 评估影响范围
- [ ] 通知相关团队
### 2. 快速定位(15分钟内)
- [ ] 检查最近部署
- [ ] 查看错误日志
- [ ] 检查依赖服务状态
- [ ] 检查基础设施指标(CPU、内存、网络)
### 3. 缓解措施(30分钟内)
- [ ] 回滚最近的变更
- [ ] 启用降级策略
- [ ] 扩容服务实例
- [ ] 切换到备用区域
### 4. 根因分析(24小时内)
- [ ] 收集所有相关数据
- [ ] 重建故障时间线
- [ ] 识别根本原因
- [ ] 制定改进措施
### 5. 事后复盘(72小时内)
- [ ] 编写事故报告
- [ ] 团队复盘会议
- [ ] 更新Runbook
- [ ] 创建改进任务
错误预算决策矩阵
def make_release_decision(budget_remaining_percent: float,
burn_rate: float) -> dict:
"""基于错误预算制定发布决策"""
if budget_remaining_percent > 50:
return {
"decision": "proceed",
"message": "预算充足,可以正常发布新功能",
"actions": ["正常发布流程", "可以承担一定风险"]
}
elif budget_remaining_percent > 20:
return {
"decision": "cautious",
"message": "预算紧张,谨慎发布",
"actions": [
"仅发布关键修复",
"加强监控",
"准备回滚计划"
]
}
elif budget_remaining_percent > 0:
if burn_rate > 1.0:
return {
"decision": "freeze",
"message": "预算即将耗尽且消耗过快,冻结发布",
"actions": [
"停止所有非紧急发布",
"专注于稳定性改进",
"7x24监控"
]
}
else:
return {
"decision": "minimal",
"message": "预算极少,仅允许紧急修复",
"actions": [
"仅允许P0级bug修复",
"每次发布需VP审批",
"加强测试覆盖"
]
}
else: # budget_remaining_percent <= 0
return {
"decision": "emergency",
"message": "预算已耗尽,进入紧急状态",
"actions": [
"停止所有发布",
"全员投入稳定性",
"可能需要延长SLO窗口",
"与客户沟通SLA风险"
]
}
# 使用示例
decision = make_release_decision(
budget_remaining_percent=15,
burn_rate=2.5
)
print(decision)
SLO治理与改进
季度SLO评审
## SLO季度评审清单
### 数据收集
- [ ] 过去季度的SLO达成率
- [ ] 错误预算消耗模式
- [ ] 重大事故统计
- [ ] 用户反馈和投诉
### 分析维度
- [ ] SLO是否过于宽松(总是100%达成)
- [ ] SLO是否过于严格(经常违反)
- [ ] 是否有新的关键用户旅程未覆盖
- [ ] 技术架构变化是否影响SLO
### 决策输出
- [ ] 调整SLO目标值
- [ ] 新增或删除SLI
- [ ] 优化监控和告警
- [ ] 更新响应流程
总结
SLO实施核心原则:
- 以用户为中心:SLO应该反映用户体验,而非内部指标
- 平衡创新与稳定:错误预算提供量化的决策依据
- 持续改进:定期评审和调整SLO
- 数据驱动:基于实际测量而非猜测
- 全员参与:SLO是整个团队的责任,不仅仅是SRE
关键收益:
- 量化的可靠性目标
- 科学的发布决策
- 减少过度工程
- 建立用户信任
- 促进跨团队协作
延伸阅读
- Google SRE Book - Service Level Objectives
- The Site Reliability Workbook
- Implementing Service Level Objectives - Alex Hidalgo
- SLOconf Resources
- OpenSLO Specification
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。