事件响应与无责事后分析:编写更好的运行手册和 SLO/SLI 定义
I’m happy to help translate the article, but I’ll need the text you’d like translated. Could you please paste the content (excluding the source line you already provided) here? Once I have the text, I’ll translate it into Simplified Chinese while preserving the original formatting, markdown syntax, and technical terms.
我们学到的
- 如何定义真正重要的 SLO
- 如何编写能够被使用的 runbooks
- 如何在不出现混乱的情况下处理事故
- 如何进行 blameless post‑mortems,防止问题再次发生
SLO 与 SLI
大多数团队要么根本没有 SLO,要么只有“假” SLO——随意挑选的数字,既不关联用户体验,也不影响工程决策。好的 SLO 能改变工作优先级:
- 健康的错误预算 → 推出新功能
- 耗尽的错误预算 → 专注可靠性
服务水平指标(SLI)应当反映用户体验,而不仅仅是服务器健康状况。
糟糕的 SLI
- CPU 利用率
- 内存使用量
- 正在运行的 pod 数量
良好的 SLI
- 请求成功率(非 5xx / 总请求)
- 第 99 百分位的请求延迟
- 数据新鲜度
示例 Prometheus 查询
# 可用性 SLI
sum(rate(http_requests_total{status!~"5.."}[5m]))
/
sum(rate(http_requests_total[5m]))
# 延迟 SLI(p99)
sum(rate(http_request_duration_seconds_bucket{le="0.3"}[5m]))
/
sum(rate(http_requests_total[5m]))
提示: 先设定宽松的目标,随后再逐步收紧。用户关心的是端到端的使用流程,而不是单个服务。
以旅程为中心的 SLO 定义 (YAML)
journeys:
- name: checkout
slo:
availability: 99.95%
latency_p99: 3s
components:
- api-gateway
- auth-service
- cart-service
- inventory-service
- payments-service
- order-service
measurement:
endpoint: /api/v1/checkout/health
rum_event: checkout_completed
错误预算阈值操作
thresholds:
- budget_remaining: 50%
actions:
- notify: slack
- budget_remaining: 25%
actions:
- freeze: non_critical_deployments
- budget_remaining: 10%
actions:
- freeze: all_deployments
- meeting: reliability_review
- budget_remaining: 0%
actions:
- focus: reliability_only
SLO 配置示例
slos:
- name: requests-availability
objective: 99.95
sli:
events:
error_query: sum(rate(http_requests_total{status=~"5.."}[{{.window}}]))
total_query: sum(rate(http_requests_total[{{.window}}]))
编写高效运行手册
好的运行手册应具备:
- 可快速浏览 – 在压力下易于快速浏览
- 可执行 – 明确的后续步骤
- 已测试 – 在预演或演练中验证
示例运行手册:Payments API 高错误率
检测
Alert: PaymentsAPIHighErrorRate
步骤 1:检查提供商状态
curl -s https://status.stripe.com/api/v2/summary.json
步骤 2:审查最近的部署
kubectl rollout history deployment/payments-api
步骤 3:如有需要回滚
kubectl rollout undo deployment/payments-api
步骤 4:检查数据库连接池
curl http://payments-api/debug/metrics | grep db_pool
自动化测试(PHP)
public function testDatabaseConnectionExhaustionRunbook(): void
{
// Simulate connection exhaustion
$this->simulateDbPoolExhaustion();
// Verify alert condition
$metrics = $this->fetchMetrics('/debug/metrics');
$this->assertLessThan(5, $metrics['db_pool_available']);
// Apply mitigation
$this->scaleServiceReplicas(10);
// Verify recovery
$this->assertTrue($this->serviceRecovered());
}
事件角色
| 角色 | 责任 |
|---|---|
| Incident Commander | 协调响应 |
| Tech Lead | 负责调试工作 |
| Comms Lead | 处理利益相关者沟通 |
严重程度等级
- SEV1 – 完全宕机或数据丢失
- SEV2 – 严重降级
- SEV3 – 轻微影响
实际事件示例
🔴 INCIDENT: Checkout Errors
Severity: SEV2
Impact: 成功率 82 %
| 角色 | 负责人 |
|---|---|
| IC | @alice |
| Tech | @bob |
| Comms | @carol |
时间线
- 14:32 – 警报触发
- 14:40 – Stripe 返回 503 错误
- 14:45 – 断路器启动
- 15:15 – 已解决
事件机器人 (PHP)
class IncidentBot
{
public function declareIncident(array $data): Incident
{
$incident = Incident::create([
'title' => $data['title'],
'severity' => $data['severity'],
'status' => 'investigating',
]);
$this->createSlackChannel($incident);
$this->notifyPagerDuty($incident);
return $incident;
}
public function resolveIncident(Incident $incident): void
{
$incident->update(['status' => 'resolved']);
$this->schedulePostmortem($incident);
}
}
事后报告摘要
摘要 – Checkout 在 43 分钟内降级。
根本原因 – 电路断路器阈值设置过高。
操作项
| 操作 | 负责人 | 截止日期 |
|---|---|---|
| 降低阈值 | @bob | Jan 22 |
| 添加警报 | @alice | Jan 23 |
操作项跟踪器 (PHP)
class ActionItemTracker
{
public function weeklyDigest(): void
{
$overdue = ActionItem::overdue()->get()->groupBy('owner');
foreach ($overdue as $owner => $items) {
$this->notifyOwner($owner, $items);
}
}
}
前后指标
| 指标 | 之前 | 之后 |
|---|---|---|
| MTTR | 4 小时 | 35 分钟 |
| 重复事件 | 4/q | 1/q |
| 剩余错误预算 | 12 % | 58 % |
可靠性作为一门学科
- SLO 告诉你何时出现问题
- 运行手册 帮助你修复它们
- 事件角色 防止混乱
- 事后分析 防止再次发生
关键要点
- 将 SLO 定义在用户旅程上,而不是单个服务上。
- 使用错误预算来指导优先级决策。
- 编写可快速浏览、可操作且定期测试的运行手册。
- 让事件保持结构化,明确角色和沟通渠道。
- 进行无责的事后分析,并坚持跟踪行动项。