故障复盘(Postmortem)流程 — 生产实践指南
日期: 2026-04-02 话题分类: SRE · 应急响应 · 持续改进 目标读者: SRE 工程师、运维工程师、技术负责人
1. 概述与背景
1.1 什么是 Postmortem?
Postmortem(事后复盘)是 SRE 文化中最核心的持续改进机制之一。它不是追责会,而是一次无责的、技术驱动的深度分析,旨在系统性地回答:
- 发生了什么?(What) — 事件的时间线和影响范围
- 为什么会发生?(Why) — 根本原因分析(Root Cause Analysis, RCA)
- 我们能做什么来防止再次发生?(Action) — 可执行的改进措施
Google 在其 SRE 书籍中明确指出:
"Postmortems should be blameless — the goal is to understand the systemic factors that contributed to the failure, not to assign blame to individuals."
1.2 为什么 Postmortem 至关重要
| 价值维度 | 具体体现 |
|---|---|
| 知识沉淀 | 将个人经验转化为组织资产,防止同类故障重复发生 |
| 系统进化 | 通过改进措施推动平台/系统稳定性持续提升 |
| 团队成长 | 工程师在分析过程中深化对系统的理解 |
| 文化塑造 | 营造"透明、无责、持续改进"的团队文化 |
| SLO 闭环 | 为 SLO 调整、错误预算消耗分析提供依据 |
1.3 Postmortem 与传统故障报告的区别
| 维度 | 传统故障报告 | Postmortem |
|---|---|---|
| 目的 | 汇报与追责 | 学习与改进 |
| 关注点 | 谁犯了错 | 哪里系统有缺陷 |
| 氛围 | 紧张、防御性 | 开放、探索性 |
| 输出 | 处罚决定 | 改进措施(Action Items) |
| 时效 | 事件后数天~数周 | 事件后 24~72 小时内启动 |
| 参与者 | 管理层 + 当事人 | 全栈工程师 + 相关方 |
2. 核心原理
2.1 无责文化(Blameless Culture)
无责文化是 Postmortem 的根基。其核心假设是:
所有故障都是系统性问题,而非个人失误。
即便某个工程师"误删了数据库",真正的问题是:
- 为什么一个人就能直接操作生产数据库?
- 为什么没有做高危操作的双人复核?
- 为什么没有可靠的备份和快速恢复机制?
无责不等于无纪律:对于故意破坏、违反明确安全规程等行为,需要另外的流程处理,不在 Postmortem 范畴内。
2.2 根本原因分析(RCA)方法论
2.2.1 5 Whys(五问法)
最经典的 RCA 方法,通过连续追问"为什么"层层深入:
问题:API 服务在 14:00 发生响应超时,持续 23 分钟
├── 为什么?→ 数据库连接池耗尽
├── 为什么?→ 慢查询导致连接长时间占用
├── 为什么?→ 某个查询缺少索引
├── 为什么?→ 新功能上线时未做数据库变更评审
└── 为什么?→ 上线流程缺少 DDL/DML 审查环节
2.2.2 故障树分析(FTA — Fault Tree Analysis)
自顶向下演绎分析,从顶事件(故障现象)逐层分解为与/或门逻辑,直到找到基本事件(根因):
[API 响应超时]
│
┌─────────────┼─────────────┐
AND OR
│ │
[数据库不可达] [上游服务超时]
/ \ │
[网络故障] [DB连接池耗尽] [依赖服务响应慢]
2.2.3 冰山理论 — 故障的深层原因
┌─────────────────────┐
│ 冰山表层(直接原因) │ ← 看得见
│ "工程师误删了数据" │
└──────────┬──────────┘
│
┌──────────▼──────────┐
│ 冰山水下(系统原因) │ ← 看不见
│ - 缺少权限管控 │
│ - 上线流程不完善 │
│ - 监控告警缺失 │
│ - 变更审批缺失 │
│ - 备份恢复机制缺失 │
└──────────────────────┘
2.3 错误预算(Error Budget)与 Postmortem 的关系
Postmortem 的改进效果可以通过错误预算消耗率量化:
错误预算 = 1 - SLO(以月为周期)
例如:SLO = 99.9%,则月度错误预算 = 0.1% × 30天 × 24小时 × 60分 = 43.2 分钟
| 错误预算状态 | 含义 | Postmortem 策略 |
|---|---|---|
| 消耗率 < 50% | 系统稳定 | 持续当前实践 |
| 消耗率 50%~100% | 需要关注 | 优先处理高优先级 Action Items |
| 消耗率 > 100% | SLO 已失守 | 立即启动深度复盘,调整 SLO 或加大改进力度 |
2.4 分布式追踪与 Postmortem 的协同
在微服务架构中,单次故障往往涉及多个服务。Postmortem 需要结合分布式追踪数据(如 Jaeger、Zipkin、OpenTelemetry)重建完整调用链路:
- 识别 span 层级中的异常根因 span
- 分析跨服务的传播延迟与级联失败
- 结合日志关联 trace_id,实现全链路回放
3. 主要功能与应用场景
3.1 Postmortem 的触发条件
| 触发级别 | 条件 | 响应时限 |
|---|---|---|
| P0 — 重大 | 核心服务不可用 > 30 分钟,影响所有用户 | 24h 内启动 Postmortem |
| P1 — 严重 | 服务降级 > 2 小时,或影响 > 30% 用户 | 48h 内启动 Postmortem |
| P2 — 中等 | 非核心功能故障,影响 < 30% 用户 | 72h 内启动 Postmortem |
| P3 — 轻微 | 局部小故障,自愈或快速修复 | 批量月度复盘 |
3.2 关键场景
场景一:单点故障引发的级联崩溃
背景:某电商平台促销期间,库存服务单节点 OOM,导致所有下游服务不可用。
Postmortem 分析重点:
- 为什么没有冗余?
- 为什么单节点 OOM 会影响全局流量?
- 熔断机制是否生效?
- 为什么促销前没有做容量压测?
场景二:配置变更引发的大规模故障
背景:一次配置推送误将生产环境的缓存 TTL 从 300s 改为 0,导致数据库被打穿。
Postmortem 分析重点:
- 为什么没有配置变更评审?
- 为什么没有灰度发布配置变更?
- 为什么没有配置变更的可观测性(变更前后监控对比)?
- 为什么数据库没有连接限流保护?
场景三:依赖外部服务的连锁故障
背景:第三方支付网关超时,导致订单服务线程池耗尽,最终拖垮整个交易链路。
Postmortem 分析重点:
- 是否有熔断和降级预案?
- 是否正确设置了超时时间?
- 是否有过载保护机制?
- 依赖服务的健康检查是否有效?
3.3 Postmortem 工具链
| 工具类别 | 推荐工具 | 用途 |
|---|---|---|
| 事件管理 | PagerDuty、Opsgenie | 记录事件触发、响应时间 |
| 协作平台 | Jira、Linear、Notion | 跟踪 Action Items 执行 |
| 分布式追踪 | Jaeger、Zipkin、AWS X-Ray | 定位跨服务根因 |
| 日志聚合 | ELK Stack、Loki、Grafana Loki | 全量日志关联分析 |
| 会议协作 | 飞书文档、Confluence、Google Docs | 文档编写与协作 |
| 自动化 | runbooks-as-code、Blameless | 标准化 Postmortem 流程 |
4. 部署与安装步骤
4.1 推荐工具:Blameless(开源 Postmortem 平台)
Blameless 是一个专门为 SRE Postmortem 设计的开源平台,支持模板化、自动化和流程追踪。
4.1.1 环境要求
# 最低要求
- CPU: 2 cores
- RAM: 4 GB
- Disk: 20 GB
- Docker: 20.10+
- Docker Compose: 1.29+
- Node.js: 16+ (前端构建)
- Go: 1.18+ (后端服务)
4.1.2 快速部署(Docker Compose)
# 1. 克隆仓库
git clone https://github.com/blamelesshq/blameless.git
cd blameless
# 2. 配置环境变量
cat > .env << 'EOF'
BLAMELESS_SECRET_KEY=your-secret-key-here
DATABASE_URL=postgresql://blameless:password@localhost:5432/blameless
REDIS_URL=redis://localhost:6379
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=postmaster@example.com
SMTP_PASSWORD=your-smtp-password
FROM_EMAIL=postmaster@example.com
EOF
# 3. 启动服务
docker-compose up -d
# 4. 验证服务状态
docker-compose ps
# 预期输出:
# NAME COMMAND SERVICE
# blameless-app "docker-entrypoint…" app
# blameless-db "docker-entrypoint…" postgres
# blameless-redis "docker-entrypoint…" redis
# blameless-nginx "nginx -g 'daemon of…" nginx
# 5. 访问 Web UI
# 浏览器打开 http://localhost:3000
# 默认管理员账号: admin@blameless.io / admin123
4.1.3 配置外部数据库(生产环境)
# 生产环境建议使用独立的 PostgreSQL
# 编辑 docker-compose.yml 中的 postgres 服务配置
services:
postgres:
image: postgres:15-alpine
environment:
POSTGRES_DB: blameless
POSTGRES_USER: blameless
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
restart: always
networks:
- blameless-network
app:
depends_on:
- postgres
- redis
environment:
DATABASE_URL: postgresql://blameless:${POSTGRES_PASSWORD}@postgres:5432/blameless
volumes:
postgres_data:
4.1.4 与 PagerDuty 集成配置
# 在 .env 中添加 PagerDuty 配置
cat >> .env << 'EOF'
PAGERDUTY_API_KEY=your-pagerduty-api-key
PAGERDUTY_SERVICE_ID=your-service-id
EOF
4.2 轻量替代方案:使用飞书文档模板
如果不方便部署独立平台,可以使用飞书文档建立标准化 Postmortem 模板:
# 创建标准目录结构
mkdir -p postmortems/{2026,template}
cd postmortems
# 创建 Postmortem 模板
cat > template/postmortem-template.md << 'TEMPLATE'
# Postmortem 模板
## 事件概览
- **事件编号**: INC-YYYYMMDD-NNN
- **严重级别**: P0/P1/P2/P3
- **发生时间**: YYYY-MM-DD HH:MM ~ HH:MM (UTC+8)
- **持续时长**: XX 分钟
- **影响范围**: 描述受影响的服务、用户比例、数据影响
- **触发来源**: 告警/用户反馈/内部发现
- **发现时间**: YYYY-MM-DD HH:MM
- **恢复时间**: YYYY-MM-DD HH:MM
- **负责人**: @xxx
## 时间线(Timeline)
| 时间 | 事件 | 操作人 |
|---|---|---|
| HH:MM | 事件开始 | - |
| HH:MM | 告警触发 |监控系统 |
| HH:MM | 值班工程师响应 | @xxx |
| HH:MM | 开始排查 | @xxx |
| HH:MM | 发现根因 | @xxx |
| HH:MM | 执行修复操作 | @xxx |
| HH:MM | 服务恢复 | @xxx |
| HH:MM | 事后验证完成 | @xxx |
## 影响评估
### 业务影响
- ...
### 技术影响
- ...
### 用户影响
- ...
## 根因分析
### 直接原因
...
### 根本原因(5 Whys)
...
### 故障传播路径
...
## 改进措施(Action Items)
| 序号 | 改进措施 | 负责人 | 优先级 | 截止日期 | 状态 |
|---|---|---|---|---|---|
| 1 | ... | @xxx | P0 | YYYY-MM-DD | 待处理 |
## 经验教训(Lessons Learned)
### 做得好(What Went Well)
- ...
### 可以改进(What Could Be Improved)
- ...
### 关键洞察(Key Takeaways)
- ...
## 参考资料
- 监控大盘链接
- 日志查询链接
- 变更记录链接
- 相关 Incidents 链接
TEMPLATE
4.3 自动化脚本:Postmortem 辅助生成
#!/bin/bash
# postmortem-gen.sh — 自动化生成 Postmortem 文档骨架
# 使用方法: ./postmortem-gen.sh 20260402 001 P1
set -e
DATE=$1
SEQ=$2
SEVERITY=${3:-P2}
YEAR=${DATE:0:4}
MONTH=${DATE:4:2}
DAY=${DATE:6:2}
INCIDENT_ID="INC-${DATE}-${SEQ}"
mkdir -p "postmortems/${YEAR}/${MONTH}"
OUTPUT_FILE="postmortems/${YEAR}/${MONTH}/${INCIDENT_ID}.md"
cat > "$OUTPUT_FILE" << EOF
# Postmortem: ${INCIDENT_ID}
> 生成时间: $(date '+%Y-%m-%d %H:%M:%S')
> 严重级别: ${SEVERITY}
> 状态: 待填写
## 事件概览
- **事件编号**: ${INCIDENT_ID}
- **严重级别**: ${SEVERITY}
- **发生时间**: ${YEAR}-${MONTH}-${DAY} HH:MM ~ HH:MM (UTC+8)
- **持续时长**: 待填写
- **影响范围**: 待填写
- **触发来源**: 待填写
- **发现时间**: 待填写
- **恢复时间**: 待填写
- **负责人**: 待填写
## 时间线(Timeline)
| 时间 | 事件 | 操作人 |
|---|---|---|
| HH:MM | 待填写 | - |
## 影响评估
### 业务影响
- 待填写
### 技术影响
- 待填写
### 用户影响
- 待填写
## 根因分析
### 直接原因
待填写
### 根本原因(5 Whys)
待填写
### 故障传播路径
待填写
## 改进措施(Action Items)
| 序号 | 改进措施 | 负责人 | 优先级 | 截止日期 | 状态 |
|---|---|---|---|---|---|
| 1 | 待填写 | 待填写 | P1 | 待填写 | 待处理 |
## 经验教训(Lessons Learned)
### 做得好(What Went Well)
- 待填写
### 可以改进(What Could Be Improved)
- 待填写
### 关键洞察(Key Takeaways)
- 待填写
## 参考资料
- 监控大盘: 待填写
- 日志查询: 待填写
- 变更记录: 待填写
EOF
echo "✅ Postmortem 文档已生成: $OUTPUT_FILE"
echo " 事件编号: ${INCIDENT_ID}"
# 保存脚本并添加执行权限
chmod +x postmortem-gen.sh
# 使用示例
./postmortem-gen.sh 20260402 001 P1
# ✅ Postmortem 文档已生成: postmortems/2026/04/INC-20260402-001.md
5. 常见问题与排查
5.1 Postmortem 常见陷阱
坑 1:变成追责会(The Blame Game)
问题表现:
- 会议气氛紧张,大家互相推卸责任
- 讨论焦点集中在"谁做了什么"而非"系统哪里有缺陷"
- 工程师不愿意坦诚发言,担心被追责
解决方案:
- 明确 Postmortem 的无责原则,在会议开始前宣读
- 主持人(Facilitator)把控讨论方向,及时转移话题
- 邀请高层旁观但不允许参与讨论,避免权力压制
- 使用"系统因素"而非"人为失误"来描述问题
坑 2:根因分析浅尝辄止
问题表现:
- 找到第一个"原因"就停止分析
- 根因停留在表面("服务器宕机了"),没有深入
- 5 Whys 只问了 2 个"为什么"就得出结论
解决方案:
- 强制要求至少 5 轮 Why 分析
- 使用故障树分析(FTA)补充
- 设立"根因判定检查点":所有 Action Items 追溯到哪个层级?
坑 3:Action Items 不具体、无法落地
问题表现:
- Action Items 过于宏观,如"加强监控""提高稳定性"
- 没有明确的负责人和截止日期
- 后续无人跟进,Action Items 石沉大海
解决方案:
- 每个 Action Item 必须满足 SMART 原则:
- Specific(具体的)
- Measurable(可衡量的)
- Achievable(可实现的)
- Relevant(相关的)
- Time-bound(有时限的)
- 建立 Action Items 追踪机制,定期 Review
- 在周会上 Review 上一次 Postmortem 的 Action Items 进展
坑 4:Postmortem 启动太晚,记忆模糊
问题表现:
- 事件发生后一周才启动 Postmortem
- 关键细节已经被遗忘
- 相关工程师已切换到其他项目,难以召集
解决方案:
- 设定明确的响应时限:P0 事件 24h 内启动
- 事件仍在进行时就开始记录时间线(实时文档)
- 使用自动化工具收集告警、指标、日志等客观数据
- 确保值班工程师当天提交初步时间线
坑 5:过度分析小故障
问题表现:
- 所有小故障都做完整 Postmortem
- 消耗大量团队精力在不重要的事件上
- 工程师对 Postmortem 产生抵触情绪
解决方案:
- 明确 Postmortem 触发条件(参考第 3.1 节)
- P3 级故障批量月度复盘即可
- 使用"轻量复盘"(Quick Retro)处理小故障
5.2 排查工具推荐
从告警到 Postmortem 的数据收集
#!/bin/bash
# collect-evidence.sh — 自动化收集故障证据
INCIDENT_ID=$1
OUTPUT_DIR="./evidence/${INCIDENT_ID}"
mkdir -p "$OUTPUT_DIR"
echo "=== 收集告警数据 ==="
# 导出故障时间窗口的告警记录
curl -s "http://prometheus/api/v1/query?query=ALERTS{alertname=~'.*'}" \
| jq '.data.result[] | select(.metric.alertname=="YourAlert")' \
> "$OUTPUT_DIR/alerts.json"
echo "=== 收集 Metrics ==="
# 导出服务关键指标
curl -s "http://prometheus/api/v1/query_range?query=up&start=${START}&end=${END}&step=60s" \
> "$OUTPUT_DIR/metrics.json"
echo "=== 收集最近变更记录 ==="
# 导出 CI/CD 变更记录(假设使用 ArgoCD)
argocd app history your-app-name \
--output json > "$OUTPUT_DIR/deployments.json"
echo "=== 收集 Kubernetes Events ==="
kubectl get events --all-namespaces \
--sort-by='.lastTimestamp' \
-o yaml > "$OUTPUT_DIR/k8s-events.yaml"
echo "=== 证据已保存到 ==="
echo "$OUTPUT_DIR"
ls -la "$OUTPUT_DIR"
5.3 敏感信息处理
# Postmortem 文档脱敏脚本
#!/bin/bash
# sanitize-postmortem.sh
INPUT=$1
OUTPUT=$2
# 替换内部 IP
sed -E 's/10\.[0-9]+\.[0-9]+\.[0-9]+/[INTERNAL_IP]/g' "$INPUT" \
| sed -E 's/172\.(1[6-9]|2[0-9]|3[0-1])\.[0-9]+\.[0-9]+/[INTERNAL_IP]/g' \
| sed -E 's/192\.168\.[0-9]+\.[0-9]+/[INTERNAL_IP]/g' \
# 替换内部域名
| sed -E 's/[a-zA-Z0-9._-]+\.(internal|local|intranet|company)\.[a-z]{2,}/[INTERNAL_DOMAIN]/g' \
# 替换密钥信息
| sed -E 's/(password|token|secret|key)["\s:=]+[^"<\s]+/[REDACTED]/gi' \
# 替换用户个人信息
| sed -E 's/[A-Za-z0-9._%+-]+@company\.com/[USER_EMAIL]/g' \
> "$OUTPUT"
echo "脱敏完成: $OUTPUT"
6. 生产实践建议
6.1 建立 Postmortem 文化
┌─────────────────────────────────────────────────────┐
│ Postmortem 成熟度模型 │
├─────────────────────────────────────────────────────┤
│ Level 5 - 持续优化: Postmortem 驱动架构演进 │
│ Level 4 - 自动化追踪: Action Items自动追踪和告警 │
│ Level 3 - 标准化流程: 模板化、时限明确、强制执行 │
│ Level 2 - 有记录: 有文档但执行不统一 │
│ Level 1 - 初始: 无固定流程 │
└─────────────────────────────────────────────────────┘
建议从 Level 3 起步:
- 强制使用标准化模板
- 明确触发条件和响应时限
- 建立 Action Items 追踪机制
- 在团队例会上定期 Review
6.2 Action Items 优先级与分工
| 优先级 | 定义 | 处理时限 | 适用场景 |
|---|---|---|---|
| P0 — 最高 | 立即修复,防止同类事件再次发生 | 72 小时内 | 核心架构缺陷、重大安全风险 |
| P1 — 高 | 影响稳定性的系统性缺陷 | 1 周内 | 非核心但关键的改进 |
| P2 — 中 | 优化项 | 1 个月内 | 提升效率的改进 |
| P3 — 低 | 长期改进项 | 季度内 | 架构演进相关 |
6.3 质量检查清单(Postmortem Review Checklist)
在正式发布 Postmortem 文档前,使用以下清单进行自检:
## Postmortem 质量检查清单
### 概览
- [ ] 事件编号、级别、时间线完整准确
- [ ] 影响范围描述具体(有数据支撑)
- [ ] 负责人明确
### 根因分析
- [ ] 根因至少追问 5 层 Why
- [ ] 区分了直接原因和根本原因
- [ ] 有故障传播路径图或文字说明
### Action Items
- [ ] 每个 Action Item 满足 SMART 原则
- [ ] 所有 Action Items 有明确的负责人
- [ ] 所有 Action Items 有明确的截止日期
- [ ] 优先处理 P0/P1 级改进
### 经验教训
- [ ] 记录了做得好的地方(不可只总结失败)
- [ ] 关键洞察对团队有实际指导意义
### 发布
- [ ] 文档经过至少 2 人 Review
- [ ] 敏感信息已脱敏
- [ ] 相关团队已同步
- [ ] Action Items 已录入跟踪系统(Jira/Linear)
6.4 与 CI/CD 集成的自动化触发
# .gitlab-ci.yml — 与 GitLab CI 集成
# 当生产环境部署后出现告警时,自动创建 Postmortem 草稿
create_postmortem_on_failure:
stage: post-deploy
script:
- |
# 检测部署后 30 分钟内是否有 P0/P1 告警
ALERT_COUNT=$(curl -s \
"http://prometheus/api/v1/query?query=ALERTS{severity=~'critical|warning'}" \
| jq '[.data.result[] | select(.metric.job=="production")] | length')
if [ "$ALERT_COUNT" -gt 3 ]; then
echo "检测到 $ALERT_COUNT 个告警,创建 Postmortem..."
# 调用 Blameless API 创建 Postmortem 草稿
curl -X POST "http://blameless-api/internal/v1/postmortems" \
-H "Authorization: Bearer $BLAMELESS_TOKEN" \
-d "{\"title\":\"Auto-triggered: ${CI_COMMIT_SHA}\",\"severity\":\"P1\"}"
fi
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: manual
6.5 指标化评估 Postmortem 效果
| 指标 | 目标值 | 采集方法 |
|---|---|---|
| Action Items 完成率 | > 80% 在截止日期前完成 | 跟踪系统 |
| 同类事件重复发生率 | 年度下降 30% | Incident 数据库 |
| Postmortem 发布及时率 | > 90% 在 72h 内发布 | Postmortem 平台 |
| Action Items 平均处理时长 | < 14 天(P0/P1) | 跟踪系统 |
| 平均恢复时间(MTTR) | 季度环比下降 20% | 监控数据 |
7. 参考资料
经典文献
Google SRE Book — Chapter 9: Postmortem Culture: Learning from Failure
- https://sre.google/sre-book/postmortem-culture/
- Google 官方对 Postmortem 的权威定义
Google SRE Book — Chapter 15: Reducing Toil through Automation
PagerDuty: The Blameless Postmortem
- https://postmodem.pagerduty.com/
- PagerDuty 官方 Postmortem 最佳实践指南
The Site Reliability Workbook — Chapter 6: SRE Reviews
开源工具
Blameless (GitHub)
- https://github.com/blamelesshq/blameless
- 专为 SRE Postmortem 设计的开源平台
Mozilla's Postmortem Templates
- https://wiki.mozilla.org/Postmortem
- Mozilla 贡献的 Postmortem 模板集合
Atlassian Incident Management
- https://www.atlassian.com/incident-management
- 与 Jira 深度集成的 Incident 管理方案
行业实践
Netflix: Chaos Engineering
- https://Netflix.github.io/chaosmonkey/
- 通过主动故障注入验证系统韧性
Amazon AWS Postmortem Template
- https://aws.amazon.com/premiumsupport/technology/posthum/
- AWS 官方 Postmortem 模板
Runbooks Automation (Netflix)
- https://netflix.github.io/openvpcal/
- 将人工操作固化为可执行 Runbook
工具文档
Prometheus Alerting
- https://prometheus.io/docs/alerting/latest/overview/
- 用于收集 Postmortem 所需的告警证据
OpenTelemetry Distributed Tracing
附录:Postmortem 完整示例
示例事件
事件编号:INC-20260402-001 事件概述:某 SaaS 平台支付服务在 14:23 UTC+8 发生响应超时,持续 23 分钟,导致 15% 的订单支付失败。
完整 Postmortem 示例
⚠️ 以下为完整示例,实际使用时请替换为真实数据。
# Postmortem: INC-20260402-001 — 支付服务超时故障
## 事件概览
- **事件编号**: INC-20260402-001
- **严重级别**: P1
- **发生时间**: 2026-04-02 14:23 ~ 14:46 (UTC+8)
- **持续时长**: 23 分钟
- **影响范围**:
- 支付成功率从 99.8% 降至 84.7%
- 约 2,300 笔订单支付失败
- 影响 GMV 约 ¥128,000
- **触发来源**: PagerDuty P1 告警(支付服务 P99 延迟 > 5s)
- **发现时间**: 14:23
- **恢复时间**: 14:46
- **负责人**: @wang-lei
## 时间线(Timeline)
| 时间 | 事件 | 操作人 |
|---|---|---|
| 14:20 | 营销活动开启,支付请求量突增 500% | — |
| 14:23 | 支付服务 P99 延迟超过 5s,触发 P1 告警 | PagerDuty |
| 14:23 | 值班工程师 @zhang-wei 接通,开始排查 | @zhang-wei |
| 14:26 | 排查发现数据库连接池使用率 100% | @zhang-wei |
| 14:29 | 尝试紧急扩容连接池参数,未生效 | @zhang-wei |
| 14:32 | 邀请 DBA @li-ming 加入排查 | @zhang-wei |
| 14:35 | 发现某慢查询(订单聚合报表)占用大量连接 | @li-ming |
| 14:38 | 从数据库 Kill 该慢查询 | @li-ming |
| 14:40 | 连接池使用率开始下降,服务逐步恢复 | @li-ming |
| 14:46 | 所有指标恢复正常 | @zhang-wei |
| 15:00 | 事后验证:补发短信通知受影响用户 | @zhang-wei |
## 影响评估
### 业务影响
- 2,300 笔订单支付失败,直接损失 GMV ¥128,000
- 用户投诉工单增加 340 条
- 品牌信誉受损(社交媒体负面反馈)
### 技术影响
- 支付服务 CPU 使用率飙升至 98%
- 数据库连接池(max_connections=100)耗尽
- 下游订单服务产生 2,300 笔超时订单
### 用户影响
- 2,300 名用户遇到支付失败
- 订单自动保留 30 分钟,用户可重试
- 事后通过短信通知受影响用户
## 根因分析
### 直接原因
某报表查询缺少索引,在并发场景下扫描全表,导致数据库连接长时间占用。
### 根本原因(5 Whys)
问题:支付服务响应超时 23 分钟 ├── 为什么?→ 数据库连接池耗尽 ├── 为什么?→ 慢查询占用大量数据库连接 ├── 为什么?→ 订单聚合报表查询全表扫描 ├── 为什么?→ 该查询字段缺少复合索引 ├── 为什么?→ 新功能上线时未进行数据库变更评审 ← 根本原因 └── 为什么?→ 上线流程缺少 DDL/DML 审查环节 ← 根本原因
### 故障传播路径
营销流量峰值 (500%) │ ▼ 支付请求激增 │ ├─→ [正常] 缓存层 │ └─→ [堆积] 数据库层 │ ├─→ [慢查询占用连接] 报表查询 │ │ │ ▼ 缺少索引,全表扫描 │ 占用 80+ 连接 │ └─→ [阻塞] 支付核心查询 │ ▼ 连接池耗尽 (100/100) │ ▼ 支付服务 P99 延迟 > 5s │ ▼ 2,300 笔支付失败
## 改进措施(Action Items)
| 序号 | 改进措施 | 负责人 | 优先级 | 截止日期 | 状态 |
|---|---|---|---|---|---|
| 1 | 为报表查询字段添加复合索引 | @li-ming | P0 | 2026-04-03 | ✅ 已完成 |
| 2 | 建立 DDL/DML 上线审查流程,所有数据库变更必须 Review | @wang-lei | P0 | 2026-04-07 | 🔄 进行中 |
| 3 | 上线 Chaos Engineering,验证数据库故障场景 | @zhang-wei | P1 | 2026-04-14 | 📋 待开始 |
| 4 | 为支付服务添加连接池使用率监控和告警 | @zhang-wei | P1 | 2026-04-09 | 🔄 进行中 |
| 5 | 编写数据库变更 Checklists,纳入上线流程 | @wang-lei | P1 | 2026-04-10 | 📋 待开始 |
| 6 | 增加订单支付超时后的自动重试机制 | @chen-yu | P2 | 2026-04-21 | 📋 待开始 |
| 7 | 添加支付服务慢查询告警(> 500ms) | @zhang-wei | P1 | 2026-04-09 | 🔄 进行中 |
## 经验教训(Lessons Learned)
### 做得好(What Went Well)
- ✅ 值班工程师 2 分钟内接通,快速响应
- ✅ 告警信息准确,帮助快速定位数据库层
- ✅ DBA 配合紧密,快速 Kill 慢查询
- ✅ 用户通知和补偿机制执行顺畅
### 可以改进(What Could Be Improved)
- ⚠️ 上线流程缺少数据库变更评审环节
- ⚠️ 缺乏慢查询实时监控和告警
- ⚠️ 连接池容量在设计时未充分考虑峰值场景
- ⚠️ 缺少 Chaos Engineering 验证数据库韧性
### 关键洞察(Key Takeaways)
- 💡 **变更管理是 SRE 的生命线**:看似微小的数据库变更可能引发灾难性故障
- 💡 **监控要有分层**:除了服务层监控,还要有基础设施层(连接池)的细粒度监控
- 💡 **主动验证优于被动救火**:Chaos Engineering 应该在故障发生前找到系统弱点
## 参考资料
- 监控大盘: https://grafana.example.com/d/inc-20260402-001
- 数据库慢查询日志: https://loki.example.com/queries
- 变更记录: https://argocd.example.com/applications/payment-service
- 相关文档: 数据库变更 SOP(内部 Wiki)
文档版本:v1.0 | 生成日期:2026-04-02 | 有效期至:下次更新 如有疑问或改进建议,请联系 SRE 团队。