故障复盘(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)重建完整调用链路:

  1. 识别 span 层级中的异常根因 span
  2. 分析跨服务的传播延迟级联失败
  3. 结合日志关联 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 起步

  1. 强制使用标准化模板
  2. 明确触发条件和响应时限
  3. 建立 Action Items 追踪机制
  4. 在团队例会上定期 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. 参考资料

经典文献

  1. Google SRE Book — Chapter 9: Postmortem Culture: Learning from Failure

  2. Google SRE Book — Chapter 15: Reducing Toil through Automation

  3. PagerDuty: The Blameless Postmortem

  4. The Site Reliability Workbook — Chapter 6: SRE Reviews

开源工具

  1. Blameless (GitHub)

  2. Mozilla's Postmortem Templates

  3. Atlassian Incident Management

行业实践

  1. Netflix: Chaos Engineering

  2. Amazon AWS Postmortem Template

  3. Runbooks Automation (Netflix)

工具文档

  1. Prometheus Alerting

  2. 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 团队。

results matching ""

    No results matching ""