防止同一故障再次发生的文档
每次重大故障都是让系统变得更可靠的机会——或者是在六个月后重复同样的错误。这种差异几乎完全取决于你的团队是否撰写有效的故障分析报告。大多数团队都没有做到。故障分析报告只是为了满足流程要求而撰写,被归档在维基中,之后再也不会被参考。本指南涵盖了那些真正能够改变行为的故障分析报告与”文档表演”之间的区别。
核心理念:无责分析
Google的SRE推广了无责故障分析的理念,其理由是:当工程师害怕被指责时,他们会隐藏信息。当他们隐藏信息时,你就无法获得实际情况的完整画面。当你没有完整的画面时,你的预防措施只会解决症状而不是根本原因。
无责并不意味着对真正鲁莽的行为没有后果。这意味着默认的假设是,人们根据当时可获得的信息做出了合理的决定。问题不应该是”谁推送了有问题的代码?”而应该是”是什么条件使得这段代码能够进入生产环境并导致故障?”
如果一个人犯了错误,应该问:是什么使得这个错误成为可能?答案几乎总是流程缺陷、防护措施缺失、运行手册不明确或测试不足——而不是个人能力不足。
实用的故障分析报告模板
这是一个在多个高可靠性工程团队中经过实战考验的模板:
# 事后分析:[服务名称] 停机事件 - [日期]
## 事件摘要
- **日期/时间**:2026-03-15 14:23 UTC – 16:47 UTC
- **持续时间**:2小时24分钟
- **影响**:100%用户无法进行支付处理;
约85,000美元交易延迟
- **严重性**:SEV-1
- **事件指挥官**:[姓名]
- **状态**:已解决
## 时间线(UTC)
| 时间 | 事件 |
|-------|-------|
| 14:20 | v2.4.1 部署完成至生产环境 |
| 14:23 | PagerDuty 警报:payment_success_rate < 95% |
| 14:31 | 值班工程师确认,开始调查 |
| 14:38 | 识别到数据库连接错误激增 |
| 14:45 | 假设:新重试逻辑导致连接池耗尽 |
| 15:02 | 开始回滚 v2.4.1 |
| 15:11 | 回滚完成;支付成功率正在恢复 |
| 16:47 | 确认完全恢复;事件关闭 |
## 根本原因
v2.4.1 部署引入了一个针对支付网关调用失败的重试机制。
重试逻辑使用固定的0ms延迟,没有熔断器。在网关错误率升高的情况下
(网关自身从14:18开始降级),每个请求最多产生5次重试尝试,
在3分钟内耗尽了数据库连接池(配置为50个连接)。
## 促成因素
1. **缺少熔断器**:没有机制阻止对降级依赖的重试。
2. **不充分的负载测试**:重试逻辑在正常负载下进行了测试,
而不是在实际中会面临的升高错误率情况下。
3. **连接池监控缺失**:没有连接池利用率 > 80% 的警报。
4. **网关并发降级**:支付网关在部署前5分钟开始降级,
增加了触发问题重试行为的错误率。
## 做得好的地方
- PagerDuty 警报在影响开始后3分钟内触发
- 值班工程师有清晰的回滚程序运行手册
- 从开始到回滚完成用时9分钟
- 客户支持团队在15分钟内得到通知
## 行动项目
| 行动 | 负责人 | 截止日期 | 优先级 |
|--------|-------|----------|----------|
| 为支付网关客户端添加熔断器 | @sarah | 2026-03-22 | P1 |
| 为所有重试逻辑添加带抖动的指数退避 | @james | 2026-03-22 | P1 |
| 添加警报:数据库连接池利用率 > 75% | @ops-team | 2026-03-19 | P1 |
| 更新负载测试以包含升高错误率的场景 | @qa-team | 2026-04-01 | P2 |
| 将网关健康检查添加到部署检查清单 | @release-eng | 2026-03-25 | P2 |
## 检测有效性
**检测时间**:3分钟(良好—警报及时触发)
**诊断时间**:22分钟(太慢—需要更好的连接池耗尽运行手册)
**解决时间**:2h 24m(可接受,考虑到回滚+恢复)
五个为什么:深入探究根本原因
大多数事后分析只停留在直接原因(”重试逻辑耗尽了连接池”)。五问法则则能深入挖掘:
问题1:为什么支付处理失败?
→ 数据库连接池已耗尽
问题2:为什么连接池会耗尽?
→ 每个请求都触发了多达5次快速重试
问题3:为什么重试如此激进?
→ 新的重试逻辑使用0毫秒延迟,没有断路器
问题4:为什么0毫秒延迟的重试逻辑会进入生产环境?
→ 代码审查没有标记出这个问题;负载测试没有模拟
错误率升高的情况;没有重试策略的linting规则
问题5:为什么我们没有重试策略标准?
→ 我们之前从未经历过由重试导致的故障;没有
相关政策是因为我们假设开发人员会
知道添加退避机制
在”问题5″处,你找到了真正的解决方案:制定文档化的重试策略标准,可能通过linting或库包装器来强制执行,使正确行为成为默认行为。
撰写时间线:事件重建的艺术
时间线是要求最严格事实的部分。如果出错,你将得出错误的结论。最佳实践:
- 使用日志中的实际时间戳,而不是从记忆中重建。提取你的可观测性平台的数据。
- 包含完整的告警到行动的间隔。如果告警在14:23触发,但工程师在14:31才确认,请记录这8分钟的间隔并加以检查。
- 记录错误的假设。花在错误假设上的14分钟与你最终发现的内容同样重要——这是改进运行手册的方式。
- 包含客户影响的关键节点。不仅是技术故障发生的时间,还包括客户首次遇到错误的时间。
真正能被执行的行动项
最常见的事后分析失败:行动项过于模糊、没有负责人或从未跟进。
糟糕的行动项:
- 改进重试逻辑处理
好的行动项:
- 为支付网关客户端添加断路器(Resilience4j)
参数:failure_rate_threshold=50%、wait_duration=30s、
permitted_calls_in_half_open=3
负责人:@sarah | 截止日期:2026-03-22 | 关联工单:ENG-4821
可执行的事后分析项的四个要求:
- 具体明确——确切要构建或更改什么
- 指定负责人——具体到个人,而不是团队
- 截止日期——具体日期,而不是”很快”或”下个冲刺”
- 关联到问题跟踪系统中的工单,以便在正常的冲刺工作中跟踪
事后审查会议
在会议前而不是会议期间编写事后分析文档。会议应重点关注:
- 验证时间线(所有在场人员应同意其准确性)
- 讨论根本原因(初稿可能遗漏了促成因素)
- 确定优先级并分配行动项
- 识别系统性模式(这是6个月内第3个数据库连接问题——有什么规律?)
将会议控制在60分钟内。如果会议时间更长,说明事件过于复杂,无法在一次会议中解决——应安排后续会议专门讨论行动项。
事后复盘文化:长期视角
单独的事后复盘很有价值。一个事后复盘文档库则具有变革性。当新工程师加入时,阅读最近20份事后复盘文档能让他们比任何架构图更了解系统实际是如何失效的。
每月事后复盘审查会议——团队一起阅读上月的事后复盘文档——能够揭示规律:相同的服务反复出现问题,相同团队的部署持续导致事故,相同的监控盲区不断被发现。这些规律在单个文档中不会显现,但在汇总后变得显而易见。
跟踪行动项直至完成。6个月后仍有5项未完成的行动项,这表明存在文化问题,而非文档问题。如果行动项没有被执行,事后复盘流程就缺乏实质效力。
事后复盘工具
工具不如流程重要,但某些选项确实比其他更有效:
- Confluence/Notion:易于编写,长期可发现性差。如果你能严格地进行标记和组织,这种方法可行。
- GitHub/GitLab:将事后复盘作为拉取请求——可审查、可评论、有版本控制。适合工程密集型团队。
- Rootly, Incident.io, PagerDuty:专为事件管理构建,内置事后复盘模板、从警报重建时间线以及行动项跟踪功能。对于运行关键服务的团队来说,这些工具物有所值。
将事后复盘视为学习投资
一份编写完善的事后复盘需要2-4小时才能完成。这成本不低。但考虑替代方案:同样的事件重复发生会造成数量级更高的损失——工程时间、客户信任和收入。每一次未能从中学习的生产事故,都是你浪费的学费。
最好的工程团队并非因为更谨慎而减少事故。他们减少的是重复发生的事故,因为他们从每次事故中汲取所有教训。事后复盘就是实现这一目标的机制。
