无指责复盘与故障分析方法论
一句话:无指责复盘(Blameless Postmortem)的核心理念是——每个故障都是系统设计缺陷的暴露,而非个人失误。复盘的产出不是”谁犯了错”,而是”系统哪里缺了防护”。
概述
你的 02-Issues/ 目录有 6 篇实战故障记录(502、MySQL 死锁、Docker 构建、K8s Ingress、cgroup v1/v2、阿里云 NAT),说明你有排查和记录的能力。但从”故障记录”到”系统性复盘”还差一层——需要标准化的复盘模板、根因分析方法论、和 Action Items 闭环跟踪。
故障记录 = 发生了什么 + 怎么修的
无指责复盘 = 为什么发生 + 怎么防止再发生 + 谁来落实 + 什么时候验证
无指责原则
核心理念
| 原则 | 含义 | 违反的例子 |
|---|
| 对事不对人 | 分析系统漏洞,不追究个人责任 | ❌ “张三改错了配置” → ✅ “变更流程缺少配置校验” |
| 假设善意 | 当事人在当时的上下文下做了合理决策 | ❌ “为什么不测试就上线” → ✅ “当时的测试环境不具备复现条件” |
| 关注改进 | 每个发现都要转化为可执行的改进措施 | ❌ “以后注意” → ✅ “CI 增加 XX 校验,owner: 李四,due: 8/10” |
| 欢迎所有人 | 任何人都可以参与复盘,不受层级限制 | 避免”领导说了算” |
| 公开透明 | 复盘文档全员可见,不藏着掖着 | 存到公共知识库,不存个人文件夹 |
为什么”无指责”有效
指责文化:
故障 → 找人背锅 → 当事人下次隐瞒故障 → 问题无法暴露 → 更大故障
无指责文化:
故障 → 找系统漏洞 → 改进系统防护 → 当事人下次主动报告 → 问题被消灭在早期
Google SRE 的经验:无指责文化让 MTTR 显著降低——因为人们不再害怕被惩罚,故障发现更早、报告更快、复盘更深入。
复盘模板
标准模板
# Postmortem: [故障标题]
## 基本信息
| 字段 | 内容 |
|------|------|
| 故障 ID | INC-2026-XXX |
| 严重程度 | SEV1 / SEV2 / SEV3 |
| 开始时间 | 2026-08-XX HH:MM |
| 恢复时间 | 2026-08-XX HH:MM |
| 持续时间 | XX 分钟 |
| 影响范围 | [受影响的服务/用户数/业务] |
| 故障作者 | [复盘撰写人] |
| 复审人 | [技术负责人] |
## 摘要(一段话)
[一句话描述故障:什么时间、什么服务、出了什么问题、影响什么、持续多久、怎么恢复的]
## 影响评估
- 用户影响:[受影响用户数 / 请求失败数 / 业务损失]
- 服务影响:[SLI 违反情况 / SLO 预算消耗]
- 数据影响:[是否有数据丢失 / 数据不一致]
- 上下游影响:[级联故障情况]
## 时间线
| 时间 | 事件 | 来源 |
|------|------|------|
| HH:MM | [事件描述] | [信息来源] |
## 根因分析
### 直接原因(触发原因)
[直接导致故障的操作/事件]
### 根本原因(系统原因)
[用 5-Whys 或故障树分析的结论,可参考 [[根因定位方法论]]]
### 根因列表
1. [根因 1]
2. [根因 2]
3. [根因 3]
## 修复过程
### 缓解措施(短期)
[故障发生时做了什么来恢复服务]
### 根治措施(长期)
[针对根因的长期改进]
## Action Items
| ID | 类型 | 描述 | Owner | Due Date | 优先级 | 状态 |
|----|------|------|-------|----------|--------|------|
| AI-001 | 短期修复 | [描述] | [人] | [日期] | P1 | Open |
| AI-002 | 长期改进 | [描述] | [人] | [日期] | P1 | Open |
| AI-003 | 流程改进 | [描述] | [人] | [日期] | P2 | Open |
## 经验教训
- [做对了什么]
- [做错了什么]
- [运气成分(碰巧了)]
- [下次怎么做得更好]
## 附录
- [监控截图]
- [日志片段]
- [变更记录链接]
- [相关工单链接]
5-Whys 实战
示例:MySQL 连接数超限
现象:MySQL 连接数超限,应用大面积超时
Why 1: 为什么连接数超限?
→ 应用创建了过多数据库连接
Why 2: 为什么应用创建了过多连接?
→ 连接池配置 max_open_conns=200,实际实例数 × 200 超过 MySQL max_connections
Why 3: 为什么连接池配置没有和 MySQL 容量对齐?
→ 扩容时只扩了应用实例,没评估 DB 连接数
Why 4: 为什么扩容流程没评估 DB 容量?
→ 扩容 checklist 中没有 DB 连接数检查项
Why 5: 为什么没有这个检查项?
→ 容量规划流程缺少依赖服务容量评估环节
根因:
1. 扩容 checklist 缺少 DB 连接数检查(流程缺陷)
2. 连接池配置未和 MySQL max_connections 做容量对齐(架构缺陷)
3. 缺少连接数预警告警(监控缺陷)
Action Items:
AI-001: 扩容 checklist 新增 DB 连接数检查项 [Owner: XX] [Due: 8/10] [P1]
AI-002: 连接池配置改为从配置中心动态读取,按实例数自适应 [Owner: XX] [Due: 8/15] [P1]
AI-003: 增加连接数 > 80% 预警告警 [Owner: XX] [Due: 8/08] [P1]
鱼骨图分析
核心思路
将可能的根因按维度分类,从多个角度系统排查。
graph LR
EFFECT[连接数超限] --> PEOPLE[人员]
EFFECT --> PROCESS[流程]
EFFECT --> TECH[技术]
EFFECT --> ENV[环境]
PEOPLE --> P1[扩容未评估 DB 容量]
PEOPLE --> P2[对连接池配置理解不足]
PROCESS --> PR1[无容量对齐流程]
PROCESS --> PR2[扩容 checklist 缺失]
PROCESS --> PR3[变更评审走过场]
TECH --> T1[连接池硬编码]
TECH --> T2[无连接数告警]
TECH --> T3[MySQL max_connections 未优化]
ENV --> E1[业务量突增]
ENV --> E2[实例数翻倍]
鱼骨图维度(6M 法)
| 维度 | 全称 | 检查方向 |
|---|
| Man | 人员 | 认知不足、培训不够、沟通不畅 |
| Method | 方法/流程 | 流程缺失、流程不合理、评审走过场 |
| Machine | 技术/工具 | 工具缺陷、配置不当、架构不合理 |
| Material | 材料/数据 | 数据质量、依赖版本、配置内容 |
| Measurement | 度量 | 监控缺失、告警阈值不当、指标定义错误 |
| Environment | 环境 | 流量突增、基础设施变更、外部依赖变化 |
Action Items 闭环
闭环流程
graph LR
POST[复盘产出 AI] --> ASSIGN[分配 Owner + Due]
ASSIGN --> TRACK[跟踪执行]
TRACK --> VERIFY[验证落地]
VERIFY -->|有效| CLOSE[关闭 AI]
VERIFY -->|无效| POST
CLOSE --> REVIEW[定期回顾]
REVIEW -->|同类故障减少?| YES[成功]
REVIEW -->|同类故障仍发生?| POST
AI 跟踪规范
from dataclasses import dataclass
from enum import Enum
import datetime
class AIPriority(Enum):
P1 = "P1" # 紧急,1 周内完成
P2 = "P2" # 重要,2 周内完成
P3 = "P3" # 一般,1 个月内完成
class AIType(Enum):
IMMEDIATE = "短期修复" # 直接修复故障的直接原因
ARCHITECTURE = "架构改进" # 从架构层面防止同类故障
PROCESS = "流程改进" # 改进流程/规范/checklist
MONITORING = "监控改进" # 增加监控/告警/看板
TOOLING = "工具改进" # 开发工具/自动化
class AIStatus(Enum):
OPEN = "Open"
IN_PROGRESS = "In Progress"
DONE = "Done"
VERIFIED = "Verified"
WONT_FIX = "Won't Fix"
@dataclass
class ActionItem:
id: str
type: AIType
description: str
owner: str
due_date: datetime.date
priority: AIPriority
status: AIStatus = AIStatus.OPEN
created_at: datetime.datetime = None
verified_at: datetime.datetime = None
verification_note: str = ""
def is_overdue(self) -> bool:
return datetime.date.today() > self.due_date and self.status != AIStatus.DONE
def needs_verification(self) -> bool:
return self.status == AIStatus.DONE and self.verified_at is None
AI 审查节奏
| 频率 | 审查内容 | 参与人 |
|---|
| 每日站会 | 到期 AI 进度 | AI Owner |
| 每周 SRE 例会 | 所有 Open AI 状态 | SRE 团队 |
| 每月回顾 | AI 关闭率 + 验证有效率 + 同类故障趋势 | SRE + 开发 |
| 每季度 | AI 覆盖分析(哪些根因类型没有 AI) | 技术负责人 |
复盘分级
| 级别 | 触发条件 | 参与范围 | 深度 | 产出 |
|---|
| 轻量复盘 | SEV3 / Near-Miss | 当事人 + 直属同事 | 10 行时间线 + 3 个 AI | 记录在工单 |
| 标准复盘 | SEV2 | 当事团队 + SRE | 完整模板 + 5-Whys | Postmortem 文档 |
| 深度复盘 | SEV1 / 跨团队 | 多团队 + 技术委员会 | 完整模板 + FTA + 鱼骨图 | 全员分享 |
与现有 02-Issues 的联动
你已有的 6 篇故障记录可以回溯套用本模板:
| 现有笔记 | 建议回溯练习 |
|---|
502排查总结 | 补充 5-Whys 根因分析 + Action Items |
MySQL 连接数超限与死锁排查实战 | 补充鱼骨图分析 + 扩容 checklist 改进 |
老Docker构建Bookworm报NO_PUBKEY与内存错误 | 补充 CI 流程改进 AI |
Ingress_reload_失败_health_api-tpa | 补充配置变更评审流程 AI |
K8s 容器启动失败 cgroup v1-v2 不匹配排查实战 | 补充节点准入检查 AI |
阿里云NAT网关SNAT入方向流量异常排查 | 补充网络监控覆盖 AI |
常见问题 / 坑点
| 问题 | 原因 | 解决方案 |
|---|
| 复盘变甩锅大会 | 文化问题 + 主持人引导不当 | 指定中立主持人,禁止出现人名,只说角色/流程 |
| AI 永远 Open | 没有 owner 或 owner 不认账 | 复盘会上当场认领,写进会议纪要 |
| 复盘写完就归档 | 没有跟踪和验证机制 | 用工单系统跟踪 AI,定期 review |
| 每次复盘都发现新问题 | 只修了直接原因没修根因 | 强制 5-Whys 到流程/制度层 |
| 复盘太长没人看 | 什么都往里塞 | 摘要一段话 + 时间线 + 根因 + AI,细节进附录 |
| 同类故障反复发生 | AI 没落地或落地无效 | 追踪同类故障趋势,无效 AI 重开复盘 |
关联知识
参考资源
- Google SRE Book: Postmortem Culture: Learning from Failure
- Google SRE Workbook: Postmortems
- blamelesspostmortem.com 模板
- Etsy 的 Postmortem 实践博客
学习时间
| 内容 | 日期 | 状态 |
|---|
| 复盘方法论 | 2026-08-03 | 完成:无指责原则、模板、5-Whys、鱼骨图、AI 闭环 |
| 回溯练习 | | 待用 02-Issues 素材练习 |
状态