3、误差预算核心指标:SLI指标设计、燃烧速率(Burn Rate)与剩余预算的计算逻辑

误差预算(Error Budget)是 SRE 实践的核心量化工具,它将系统可靠性从“尽可能高”的模糊目标,转化为可度量、可管理的工程指标。本章聚焦于误差预算台账中的三个核心要素:SLI(Service Level Indicator)、燃烧速率(Burn Rate)与剩余预算(Remaining Budget)。理解这三者的定义、设计原则与计算逻辑,是构建有效告警与容量规划的基础。

3.1 SLI 指标设计:从原始数据到可聚合的可靠性度量

SLI 是服务可靠性的直接量化指标,通常定义为“好事件”占总事件的比例。设计 SLI 时,需要明确三个要素:测量对象、好事件定义与时间窗口。

设计原则:SLI 应直接反映用户体验,而非内部基础设施状态。例如,对于 Web 服务,优先选择“请求成功率”而非“CPU 使用率”。

3.1.1 常见 SLI 类型与 PromQL 表达

SLI 类型 好事件定义 典型 PromQL 表达式(原始计数)
请求成功率 HTTP 状态码 < 500 sum(rate(http_requests_total{status!~"5.."}[5m]))
请求延迟(P99) 延迟 <= 200ms histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))
可用性 成功探针响应 avg(probe_success)
吞吐量 请求数 > 阈值 sum(rate(http_requests_total[5m]))

在误差预算台账中,我们通常将 SLI 聚合为时间窗口内的好事件比例:

# 计算过去 30 天的请求成功率 SLI
(
  sum(rate(http_requests_total{status!~"5.."}[30d]))
  /
  sum(rate(http_requests_total[30d]))
)

3.1.2 SLI 设计检查清单

  • 可测量性:指标是否可以从现有监控系统直接获取或计算?
  • 用户相关性:指标是否反映用户实际体验?
  • 可聚合性:指标是否支持按服务、版本、区域等维度进行聚合?
  • 稳定性:指标在正常波动下是否保持稳定,避免频繁触发告警?

3.2 燃烧速率(Burn Rate)计算逻辑

燃烧速率衡量的是错误预算消耗的速度。它定义为“实际错误率”与“SLO 允许的错误率”之比。当燃烧速率 > 1 时,表示错误预算正在以快于预期的速度消耗。

3.2.1 燃烧速率公式

Burn Rate = (1 - SLI) / (1 - SLO)

其中:

  • SLI:当前时间窗口内的实际好事件比例(例如 0.995)
  • SLO:目标好事件比例(例如 0.999)

示例:若 SLO 为 99.9%(0.999),当前 SLI 为 99.5%(0.995),则:

Burn Rate = (1 - 0.995) / (1 - 0.999) = 0.005 / 0.001 = 5

这意味着错误预算的消耗速度是预期的 5 倍。

3.2.2 多窗口燃烧速率告警策略

在实际 SRE 实践中,通常使用多窗口(例如 1 小时、5 小时、30 小时)的燃烧速率来触发不同级别的告警。下表展示了 Google SRE 推荐的典型配置:

告警级别 时间窗口 燃烧速率阈值 预算消耗比例 响应时间
Page(紧急) 1 小时 >= 14.4 2% 预算在 1 小时内烧完 立即
Page(紧急) 5 小时 >= 6 5% 预算在 5 小时内烧完 立即
Ticket(非紧急) 30 小时 >= 1 预算在 30 小时内烧完 下一个工作日
优化提示:在 PromQL 中,燃烧速率查询应使用 rate() 或 increase() 函数,并确保时间窗口与 SLO 周期对齐。避免在短窗口内使用 avg_over_time() 直接聚合 SLI,这会导致燃烧速率计算失真。

3.3 剩余预算(Remaining Budget)计算逻辑

剩余预算表示在 SLO 周期内,系统还能容忍多少错误而不违反 SLO。它是误差预算台账中最直观的“健康度”指标。

3.3.1 剩余预算公式

Remaining Budget = 1 - (Total Errors / Allowed Errors)

其中:

  • Total Errors:SLO 周期内累计的错误事件数
  • Allowed Errors:SLO 周期内允许的最大错误事件数 = 总事件数 × (1 - SLO)

示例:若 SLO 周期为 30 天,总请求数为 10,000,000,SLO 为 99.9%,则允许错误数为 10,000。若当前已发生 2,000 个错误,则:

Remaining Budget = 1 - (2000 / 10000) = 0.8 = 80%

表示还有 80% 的预算可用。

3.3.2 PromQL 实现剩余预算

# 计算 30 天窗口内的剩余预算
(
  1
  -
  (
    sum(increase(errors_total[30d]))
    /
    (
      sum(increase(requests_total[30d]))
      *
      (1 - 0.999)  # SLO = 99.9%
    )
  )
)
注意:当剩余预算接近 0 或为负数时,表示系统已经或即将违反 SLO。此时应触发紧急告警,并启动事故响应流程。剩余预算为负并不意味着系统立即不可用,而是表明在 SLO 周期内已无法通过后续的正常运行来弥补。

3.4 核心指标关系图

下图展示了 SLI、SLO、燃烧速率与剩余预算之间的逻辑关系:

误差预算核心指标关系图 原始监控数据 请求数、错误数、延迟 SLI 好事件比例 SLO 目标可靠性 聚合计算 对比 燃烧速率 错误消耗速度 剩余预算 可用错误额度 (1-SLI)/(1-SLO) 影响 关键公式 • 燃烧速率 = (1 - SLI) / (1 - SLO) • 剩余预算 = 1 - (累计错误数 / 允许错误数) • 允许错误数 = 总事件数 × (1 - SLO)

3.5 实践案例:构建误差预算台账

假设某 API 服务的 SLO 为 99.9%(30 天滚动窗口),我们需要在 Prometheus 中构建误差预算台账。以下是一个完整的 PromQL 查询集:

# 1. SLI:30 天请求成功率
sli:request_success_rate:30d = (
  sum(rate(http_requests_total{status!~"5.."}[30d]))
  /
  sum(rate(http_requests_total[30d]))
)

# 2. 燃烧速率:1 小时窗口
burn_rate:1h = (
  (1 - sli:request_success_rate:1h)
  /
  (1 - 0.999)
)

# 3. 剩余预算
remaining_budget:30d = (
  1
  -
  (
    sum(increase(http_requests_total{status=~"5.."}[30d]))
    /
    (
      sum(increase(http_requests_total[30d]))
      * 0.001
    )
  )
)
优化建议:在 PromQL 中,使用 rate() 函数时,时间窗口应至少为指标采集间隔的 4 倍,以避免数据稀疏导致的抖动。对于 30 天窗口,建议使用 increase() 而非 rate(),因为 increase() 直接返回累计值,更适合预算计算。

3.6 常见陷阱与避坑指南

  • 陷阱 1:使用 avg_over_time() 聚合 SLI 时,忽略了时间窗口内的请求量权重,导致 SLI 失真。应使用 sum(rate(...)) / sum(rate(...)) 形式。
  • 陷阱 2:燃烧速率计算中,时间窗口与 SLO 周期不匹配。例如,使用 1 小时窗口计算 30 天 SLO 的燃烧速率,可能导致误告警。
  • 陷阱 3:剩余预算为负时,未考虑“预算透支”后的恢复机制。实际上,剩余预算为负后,系统仍可正常运行,但需要在后续周期内通过更高的可靠性来“偿还”。