服务等级目标(SLO):从定义到实施的完整指南

深入讲解SLO、SLI、SLA的核心概念与区别,详解错误预算计算、SLO制定方法、告警策略设计,提供Prometheus+SLO监控的实战配置与故障响应流程。

引言

服务等级目标(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实施核心原则:

  1. 以用户为中心:SLO应该反映用户体验,而非内部指标
  2. 平衡创新与稳定:错误预算提供量化的决策依据
  3. 持续改进:定期评审和调整SLO
  4. 数据驱动:基于实际测量而非猜测
  5. 全员参与:SLO是整个团队的责任,不仅仅是SRE

关键收益:

  • 量化的可靠性目标
  • 科学的发布决策
  • 减少过度工程
  • 建立用户信任
  • 促进跨团队协作

延伸阅读

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页