SRE 事件管理:值班轮换、事后复盘、SLO/SLI/SLA 定义与错误预算管理
站点可靠性工程将软件工程纪律引入运维。其核心在于定义可靠性的含义、客观地衡量它,并在可靠性与功能迭代速度之间做出数据驱动的权衡。本指南涵盖了从值班设计到错误预算策略的完整事件管理生命周期。
SRE 可靠性框架
业务需求 --> SLA(外部承诺)
|
v
工程目标 --> SLO(内部目标,比 SLA 更严格)
|
v
测量 --> SLI(实际衡量的指标)
|
v
错误预算 = 100% - SLO 目标

定义 SLI(服务等级指标)
SLI 是服务行为的定量测量。选择能反映用户体验的 SLI:
基于请求的 SLI
# 可用性 SLI
availability_sli = good_requests / total_requests
# 其中“良好”意味着:
# - 状态码 < 500
# - 响应时间 < 500ms
# - 响应体是有效的 JSON
# 延迟 SLI
latency_sli = requests_under_threshold / total_requests
# 例如,在 < 200ms 内完成的请求
PromQL SLI 计算
# 30 天内的可用性 SLI
(
sum(rate(http_requests_total{status!~"5.."}[30d]))
/
sum(rate(http_requests_total[30d]))
)
# 延迟 SLI:请求中 < 300ms 的比例
(
sum(rate(http_request_duration_seconds_bucket{le="0.3"}[30d]))
/
sum(rate(http_request_duration_seconds_count[30d]))
)
按服务类型划分的适当 SLI
| 服务类型 | 主要 SLI | 次要 SLI |
|---|---|---|
| 面向用户的 API | 可用性 | 延迟(P99) |
| 数据管道 | 新鲜度 | 完整性 |
| 存储 | 持久性 | 吞吐量 |
| 批处理作业 | 完成率 | 持续时间 |
设置 SLO(服务等级目标)
SLO 是您对自己设定的内部目标。它们应比 SLA 更严格,以提供缓冲。
# slo-config.yaml
slos:
- name: "API Availability"
description: "成功请求的百分比"
sli:
metric: availability
query: |
sum(rate(http_requests_total{status!~"5.."}[30d]))
/ sum(rate(http_requests_total[30d]))
target: 0.999 # 99.9% = 每月约 43.8 分钟停机
window: 30d
- name: "API Latency P99"
description: "99 百分位请求延迟低于 500ms"
sli:
metric: latency
query: |
histogram_quantile(0.99,
sum by (le) (rate(http_request_duration_seconds_bucket[30d]))
) < 0.5
target: 0.95 # 95% 的时间 P99 低于 500ms
window: 30d
错误预算
错误预算是指允许的不可靠性:
错误预算 = 1 - SLO 目标
99.9% SLO => 0.1% 错误预算 => 每月 43.8 分钟
99.5% SLO => 0.5% 错误预算 => 每月 3.65 小时
99.0% SLO => 1.0% 错误预算 => 每月 7.3 小时
错误预算策略
错误预算剩余 > 50%:
- 功能开发按正常节奏进行
- 允许实验和有风险的部署
错误预算剩余 10-50%:
- 提高监控和告警灵敏度
- 所有事件都需要事后复盘
- 推迟非关键的有风险部署
错误预算剩余 < 10%:
- 功能冻结:仅进行可靠性工作
- 所有部署需要审批
- 指定事件指挥官
错误预算耗尽(0%):
- 完全冻结,直到新的预算周期
- 需要通知管理层
- 强制可靠性冲刺
值班轮换设计

轮换原则
- 主/备配对 — 每个班次都有备份
- 随太阳轮转 — 将告警路由到醒着的工程师
- 负载均衡 — 公平分配事件
- 升级路径 — 清晰的联系链
# PagerDuty 排班(通过 Terraform)
resource "pagerduty_schedule" "primary" {
name = "Backend Primary On-Call"
time_zone = "UTC"
layer {
name = "Weekly Rotation"
start = "2026-01-01T00:00:00+00:00"
rotation_virtual_start = "2026-01-01T00:00:00+00:00"
rotation_turn_length_seconds = 604800 # 1 周
users = [
pagerduty_user.alice.id,
pagerduty_user.bob.id,
pagerduty_user.carol.id,
pagerduty_user.dave.id,
]
}
}
resource "pagerduty_escalation_policy" "backend" {
name = "Backend Escalation"
rule {
escalation_delay_in_minutes = 5
target {
type = "schedule_reference"
id = pagerduty_schedule.primary.id
}
}
rule {
escalation_delay_in_minutes = 10
target {
type = "schedule_reference"
id = pagerduty_schedule.secondary.id
}
}
rule {
escalation_delay_in_minutes = 15
target {
type = "user_reference"
id = pagerduty_user.engineering_manager.id
}
}
}
值班 Runbook 模板
# 服务:Payment API
## 快速参考
- 仪表盘:https://grafana.example.com/d/payment-api
- 日志:https://kibana.example.com/app/payment-api
- Runbooks:https://wiki.example.com/runbooks/payment-api
## 告警:HighErrorRate
**严重级别:** 警告 / 严重(>5%)
**症状:** 用户无法完成结账
**调查步骤:**
1. 检查错误率仪表盘
2. grep 日志查找 5xx 错误:`kubectl logs -n production -l app=payment-api --since=10m | grep "ERROR"`
3. 检查数据库连接池:`kubectl exec -n production deploy/payment-api -- /health/db`
4. 检查上游支付提供商状态:https://status.stripe.com
**修复措施:**
- 如果数据库连接耗尽:`kubectl rollout restart deploy/payment-api -n production`
- 如果上游提供商中断:在配置映射中切换到备用提供商
- 如果是代码缺陷:回滚:`kubectl rollout undo deploy/payment-api -n production`
**升级:** 如果 30 分钟内未解决,联系 payment-team-lead
事件响应流程
严重级别
| 级别 | 用户影响 | 响应时间 | 示例 |
|---|---|---|---|
| SEV-1 | 完全中断 | 立即 | 结账不可用,100% 错误率 |
| SEV-2 | 严重降级 | 15 分钟 | >50% 错误,>10x 延迟 |
| SEV-3 | 轻微降级 | 1 小时 | 错误率升高,单个区域 |
| SEV-4 | 最小影响 | 下一个工作日 | 非关键功能不可用 |
事件指挥官角色
事件指挥官职责:
1. 声明事件严重级别
2. 建立沟通渠道(#incident-YYYY-MM-DD-description)
3. 分配角色:技术负责人、沟通负责人、记录员
4. 每 15 分钟(SEV-1)或 30 分钟(SEV-2)提供状态更新
5. 对修复措施做出执行/不执行决策
6. 声明事件已解决
7. 在 48 小时内安排事后复盘
无责事后复盘
目标是学习,而非指责。关注系统和流程,而非人。

事后复盘模板
# 事后复盘:Payment Service 中断 - 2026-05-15
**状态:** 完成
**严重级别:** SEV-1
**持续时间:** 47 分钟(14:23 UTC 至 15:10 UTC)
**影响:** 约 12,000 名用户无法完成结账;估计收入影响约 $180k
## 时间线
| 时间 (UTC) | 事件 |
|---|---|
| 14:20 | 开始部署 payment-api v2.4.1 |
| 14:23 | 告警:ErrorRate > 50%(PagerDuty) |
| 14:25 | 值班工程师确认 |
| 14:28 | 事件声明为 SEV-1 |
| 14:35 | 确定根本原因:数据库连接字符串配置错误 |
| 14:50 | 开始回滚 |
| 15:05 | 错误率恢复至基线 |
| 15:10 | 事件解决 |
## 根本原因
v2.4.1 部署引入了一项配置更改,在生产环境中使用了 staging 数据库连接字符串。该配置错误未在 CI 中被捕获,因为集成测试针对的是 mock 而非真实数据库。
## 促成因素
1. 未验证数据库连接字符串是否与预期环境匹配
2. 部署流水线在部署后未对生产环境运行冒烟测试
3. 配置管理允许在生产配置文件中出现 staging 值
## 行动项
| 行动 | 负责人 | 截止日期 | 优先级 |
|---|---|---|---|
| 添加配置验证,检测生产环境中的 staging 值 | Platform Team | 2026-05-22 | P1 |
| 在部署流水线中添加部署后冒烟测试 | DevOps Team | 2026-05-29 | P1 |
| 在 CI 中实现配置模式验证 | Backend Team | 2026-06-05 | P2 |
| 审查所有服务配置是否存在类似问题 | All Teams | 2026-06-12 | P2 |
## 做得好的方面
- 部署后 3 分钟内触发告警
- 团队通过事件频道迅速集结
- 回滚流程文档完善且执行迅速
错误预算消耗速率告警
计算消耗速率以在预算耗尽前检测到:
# 当前消耗速率(我们消耗错误预算的速度)
# 1.0 = 以 SLO 速率精确消耗
# 14.4 = 以预算允许的 14.4 倍消耗(对于 99.9% SLO,将在 2 小时内耗尽)
(1 - (
sum(rate(http_requests_total{status!~"5.."}[1h]))
/ sum(rate(http_requests_total[1h]))
)) / (1 - 0.999)
基于预算耗尽时间的告警阈值:
- 消耗速率 > 14.4 持续 1 小时且 5 分钟 = 页面(预算在 2 小时内耗尽)
- 消耗速率 > 6 持续 6 小时且 30 分钟 = 工单(预算在 5 天内耗尽)
结论
有效的 SRE 事件管理将被动救火转变为系统化的可靠性工程实践。SLI 提供用户体验的客观测量。SLO 设定与业务需求一致的进取目标。错误预算在工程和产品之间创建了关于风险容忍度的共同语言。无责事后复盘从失败中产生组织学习。这些实践共同创造了一个随时间推移不断提高可靠性的良性循环。