Engineering SRE

生产事故响应手册:从慌乱到从容的系统性方法

凌晨 3 点被报警叫醒?面对生产事故手足无措?分享我 5 年处理 100+ 起事故的实战经验,建立从事前预防到事后复盘的全流程体系。

Ioodu · · Updated: Mar 15, 2026 · 20 min read
#Incident Response #On-Call #SRE #Production #DevOps #稳定性

那个改变一切的凌晨

2021 年 12 月 18 日,凌晨 3:47。

我被刺耳的报警声惊醒。手机屏幕上闪烁着红色:「CRITICAL: Payment service down」。

我手忙脚乱地打开电脑,VPN 连接失败。尝试三次后终于连上,却发现日志系统也挂了。Dashboard 一片空白,只有 Slack 里用户愤怒的投诉刷屏。

接下来的 4 小时,是一场噩梦:

  • 我不知道问题出在哪里
  • 我不知道该联系谁
  • 我不确定回滚是否有用
  • 我不敢做重大改动,怕让事情更糟

最终,我们在早上 8 点恢复了服务——但已经损失了 300 万订单,客户满意度暴跌。

那次事故后,我发誓要建立一套系统性的响应方法。

现在,5 年过去了,我处理了 100+ 起事故,从手忙脚乱到从容应对。这篇文章分享我的完整方法论。

为什么需要事故响应体系

事故是软件的一部分

任何复杂系统都会故障。

  • Google:每年数千起事故
  • Amazon:每天有服务故障
  • Netflix: intentionally 破坏自己的系统(Chaos Monkey)

关键不是避免事故,而是快速恢复并从中学习。

没有体系的代价

维度有体系无体系
MTTR (平均恢复时间)15 分钟2-4 小时
团队压力可控极高
客户影响最小化不可控
事后学习系统化无章法
重复事故极少频繁

事故响应的三个阶段

事前准备(80% 的工作)

    ├── 监控与报警
    ├── Runbook 文档
    ├── 演练与培训
    └── 架构设计

事故发生(关键时刻)

    ├── 发现
    ├── 响应
    ├── 定位
    ├── 止损
    └── 恢复

事后复盘(成长机会)

    ├── 时间线重建
    ├── 根因分析
    ├── 改进项跟踪
    └── 知识沉淀

关键认知:80% 的工作在事前,但很多人只关注事故发生时。

第一阶段:事前准备

1. 监控体系

没有监控 = 盲人骑瞎马

监控的层次

┌─────────────────────────────────────────────────────────┐
│  业务层(Business Metrics)                             │
│  - 订单量、支付成功率、用户活跃度                        │
│  - 最重要,直接影响收入                                  │
├─────────────────────────────────────────────────────────┤
│  应用层(Application Metrics)                          │
│  - 响应时间、错误率、吞吐量                              │
│  - 服务的健康状态                                        │
├─────────────────────────────────────────────────────────┤
│  系统层(Infrastructure Metrics)                       │
│  - CPU、内存、磁盘、网络                                 │
│  - 资源使用情况                                          │
├─────────────────────────────────────────────────────────┤
│  日志(Logs)                                           │
│  - 请求日志、错误日志、审计日志                          │
│  - 详细的问题诊断信息                                    │
└─────────────────────────────────────────────────────────┘

关键指标设定

RED 方法(面向用户的服务):

  • Rate:请求量(每秒请求数)
  • Errors:错误率(百分比)
  • Duration:响应时间(分位值 p50, p95, p99)

USE 方法(面向资源):

  • Utilization:利用率
  • Saturation:饱和度
  • Errors:错误数

报警规则

好的报警

  • ✅ 可操作的(Actionable):收到报警知道要做什么
  • ✅ 具体的(Specific):指出具体哪个服务、哪个指标
  • ✅ 及时的(Timely):问题正在发生
  • ✅ 重要的(Important):需要立即处理

不好的报警

  • ❌ CPU > 80%(不一定是问题)
  • ❌ 任何错误(正常系统也有错误)
  • ❌ 预测性报警(提前 1 小时预警,结果 false positive)

我的报警分级

级别触发条件响应时间通知方式
P0服务完全不可用5 分钟电话 + Slack
P1核心功能受损15 分钟Slack + SMS
P2性能严重下降1 小时Slack
P3警告阈值4 小时邮件

2. Runbook(操作手册)

Runbook 是事故响应的救命稻草。

什么是 Runbook

针对每个可能报警的详细操作步骤。

Runbook 模板

# Service X - High Error Rate

## 症状
- 错误率 > 5%
- 影响用户登录

## 检查清单(按顺序执行)

### 1. 确认问题
- [ ] 查看 Dashboard: https://grafana.xxx.com/service-x
- [ ] 确认不是下游依赖问题
- [ ] 确认不是网络抖动

### 2. 快速止损选项

**选项 A:回滚到上一版本**
```bash
kubectl rollout undo deployment/service-x
  • 风险:可能丢失数据(如果有 schema 变更)
  • 时间:2 分钟

选项 B:扩容

kubectl scale deployment/service-x --replicas=10
  • 适用:流量激增导致
  • 时间:1 分钟

选项 C:启用降级模式

curl -X POST https://api.xxx.com/admin/degrade \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"feature": "recommendation", "level": "basic"}'
  • 适用:特定功能问题
  • 时间:30 秒

3. 根因诊断命令

查看错误日志:

kubectl logs deployment/service-x --tail=500 | grep ERROR

查看依赖服务状态:

./scripts/check-dependencies.sh service-x

4. 升级路径

如果 10 分钟内无法解决:

  • 通知 Tech Lead(电话:xxx)
  • 在 #incident-response 频道发布事故公告
  • 启动事故响应流程

5. 恢复确认

  • Dashboard 恢复正常 5 分钟
  • 无新错误日志
  • 业务指标恢复

相关文档

  • 架构图:xxx
  • 代码仓库:xxx
  • 依赖服务列表:xxx

历史事故

  • 2025-08-15: 数据库连接池耗尽,解决:扩容连接池
  • 2025-05-22: 缓存雪崩,解决:预热缓存 + 熔断

#### Runbook 维护

- [ ] 每次事故后更新 Runbook
- [ ] 每季度 review 一次
- [ ] 新服务上线必须有 Runbook
- [ ] 演练时验证 Runbook 有效性

### 3. 事故响应流程

#### 角色定义

事故指挥官(Incident Commander, IC) ├── 职责:协调响应,做关键决策 ├── 技能:了解全局,善于沟通 └── 切换:必要时可切换给其他人

技术负责人(Technical Lead, TL) ├── 职责:主导技术诊断和修复 ├── 技能:深入了解系统 └── 专注:不参与对外沟通

沟通负责人(Communications Lead, CL) ├── 职责:对内对外沟通 ├── 对外:客户通知、Status Page 更新 └── 对内:团队同步、升级通知

记录员(Scribe) ├── 职责:记录时间线和关键决策 └── 工具:共享文档(Google Doc / Notion)


**注意**:一个人可以兼任多个角色,但要明确分工。

#### 沟通模板

**事故公告模板(Slack)**:
```markdown
🚨 INCIDENT ALERT 🚨

服务:Payment API
状态:Investigating
影响:用户无法完成支付
开始时间:14:23 UTC
当前状态:团队正在调查,预计 30 分钟内更新

更新频道:#incident-2026-03-15-payment

状态更新模板(每 30 分钟)

INCIDENT UPDATE

时间:15:00 UTC(事故发生后 37 分钟)
状态:Mitigating
进展:已定位到数据库连接池耗尽,正在扩容
ETA:预计 15:30 恢复
影响:约 5000 笔支付失败

下一步:扩容完成后验证,更新 Status Page

事故关闭模板

✅ INCIDENT RESOLVED

服务:Payment API
恢复时间:15:45 UTC
总时长:1 小时 22 分钟
影响:8000 笔支付失败,已自动重试成功
根因:数据库连接池配置过小

复盘会议:明天 10:00 AM
文档链接:[Incident Report](xxx)

4. 演练(Game Day)

没有演练的体系是不完整的。

演练类型

桌面演练(Tabletop)

  • 围坐在一起,讨论假设场景
  • 不实际操作,只走流程
  • 频率:每月一次
  • 时长:1 小时

功能演练(Functional)

  • 实际模拟事故
  • 使用测试环境
  • 频率:每季度一次
  • 时长:半天

混沌工程(Chaos Engineering)

  • 生产环境随机注入故障
  • 验证系统自愈能力
  • 频率:每月一次(小规模)
  • 工具:Chaos Monkey, Litmus

演练流程

  1. 策划:定义目标、范围、场景
  2. 准备:设置监控、准备 rollback 方案
  3. 执行:注入故障,观察响应
  4. 观察:记录响应时间、决策过程
  5. 复盘:讨论改进点
  6. 改进:更新 Runbook、修复问题

演练场景示例

  • 数据库主库宕机
  • 缓存服务不可用
  • 第三方 API 超时
  • 网络分区(脑裂)
  • 证书过期
  • 配置错误导致服务不可用

5. On-Call 体系

On-Call 轮换

原则

  • 每人每次 on-call 不超过 1 周
  • 轮换后有 1 周 “cool down” 时间
  • 避免连续节假日 on-call

我的团队安排

  • 5 人轮值
  • 每人每周一次
  • 主备双岗(Primary + Secondary)

On-Call 补偿

  • 工作日 on-call:正常工资 + 调休
  • 周末 on-call:2 倍调休
  • 节假日 on-call:3 倍调休
  • 实际处理事故:额外调休

关键:On-Call 是工作,需要补偿。

On-Call 工具包

每个 on-call 工程师需要:

  • VPN 随时可连
  • 生产环境访问权限
  • 报警 App(PagerDuty/Opsgenie)
  • 团队联系方式(电话)
  • 笔记本电源充足
  • 手机流量充足(备用网络)

第二阶段:事故发生

事故响应流程图

发现报警


确认事故(5分钟内)

    ├── 是事故 → 通知团队,启动响应

    └── 误报 → 调整阈值,记录


组建响应团队(IC + TL + CL)


评估影响

    ├── 高影响 → 立即止损(回滚/降级)

    └── 低影响 → 继续诊断


定位根因


修复并验证


恢复服务


监控观察(30分钟)


事故关闭

1. 发现阶段

目标:尽快知道问题发生

关键

  • 监控覆盖全面
  • 报警渠道可靠
  • 避免报警疲劳(否则容易忽视)

2. 确认阶段

不要立即响应,先确认。

检查清单

  • 是否真实事故?(排除误报)
  • 影响范围?(多少用户、哪些功能)
  • 是否是已知问题?(查 Runbook)

时间盒:5 分钟内必须确认

3. 响应阶段

立即行动(First 5 Minutes)

  1. 通知团队

    在 #incident-response 频道发布事故公告
    @channel 通知当前 on-call 人员
  2. 组建响应团队

    • 自己担任 IC
    • 找 TL(如果不确定,请求支援)
  3. 创建事故文档

    • 使用模板创建共享文档
    • 实时记录时间线

止损优先

黄金法则:先止血,再治疗。

常见止损手段:

手段适用场景恢复时间副作用
回滚新版本引入问题2-5 分钟丢失新功能
降级部分功能问题30 秒-1 分钟体验下降
熔断下游依赖故障自动功能受限
限流流量激增1 分钟部分请求拒绝
扩容资源不足2-5 分钟成本增加

关键决策:什么时候止损 vs 继续诊断?

我的原则:

  • 如果影响 > 1000 用户或 > 1 万元损失/小时 → 立即止损
  • 如果不确定根因 → 优先止损
  • 如果有明确根因且 5 分钟可修复 → 直接修复

4. 诊断阶段

系统诊断方法

分层诊断法

用户端 → CDN → 网关 → 应用 → 缓存 → 数据库 → 外部依赖
   │       │      │       │       │       │         │
   └───────┴──────┴───────┴───────┴───────┴─────────┘
                    从外到内排查

二分法

  • 确定问题在哪个层
  • 每层用二分法缩小范围
  • 配合日志和监控定位

关键命令和工具

快速健康检查

# 服务状态
kubectl get pods

# 资源使用
top
kubectl top nodes
kubectl top pods

# 网络连通
ping
curl -v

# 数据库连接
mysql -e "SHOW PROCESSLIST;"
redis-cli ping

日志查询

# 实时日志
kubectl logs -f deployment/service-x

# 错误日志
kubectl logs deployment/service-x | grep ERROR

# 特定用户请求
kubectl logs deployment/service-x | grep "user-id: xxx"

链路追踪

  • Jaeger/Zipkin:分布式追踪
  • 找出请求在哪一步变慢/失败

5. 修复阶段

修复原则

  1. 小步快跑:小改动,快速验证
  2. 一次一个:不要同时改多个东西
  3. 随时回滚:每个改动都要能回滚
  4. 记录变更:记录所有尝试过的操作

常见修复操作

配置变更

# 修改配置并热更新
kubectl apply -f config.yaml

# 回滚配置
kubectl rollout undo configmap/app-config

代码回滚

# 查看历史版本
kubectl rollout history deployment/service-x

# 回滚到上一版本
kubectl rollout undo deployment/service-x

# 回滚到特定版本
kubectl rollout undo deployment/service-x --to-revision=3

数据库操作(谨慎!):

# 查看慢查询
mysql -e "SELECT * FROM information_schema.processlist WHERE time > 10;"

# 杀掉慢查询(如果确定是问题)
mysql -e "KILL <query_id>;"

# 扩容连接池(应用配置)

6. 恢复阶段

验证清单

  • 错误率恢复正常
  • 响应时间恢复正常
  • 业务指标恢复(订单量等)
  • 无新的错误日志
  • 持续观察 30 分钟

保持监控

  • 事故后 24 小时内密切监控
  • 准备好二次故障的应对

第三阶段:事后复盘

复盘的目的

  • 不是为了追责(Blameless)
  • 是为了学习和改进
  • 防止同类事故再次发生

复盘的时间线

时间点活动
事故后 24 小时内撰写事故时间线
事故后 48 小时内召开复盘会议
事故后 1 周内完成改进项
事故后 1 个月验证改进效果

事故时间线

详细记录每个关键事件

14:23:00 - 部署 v2.3.1 到生产环境
14:25:30 - 错误率开始上升(从 0.1% 到 1%)
14:28:00 - PagerDuty 报警触发
14:28:15 - On-call 工程师(张三)收到报警
14:30:00 - 张三确认事故,在 #incident-response 发布公告
14:32:00 - 李四加入(TL),开始诊断
14:35:00 - 定位到数据库连接池耗尽
14:38:00 - 执行扩容,连接池从 50 增加到 100
14:40:00 - 错误率开始下降
14:45:00 - 服务完全恢复,错误率回到正常水平
14:50:00 - 持续监控 5 分钟,确认稳定
15:00:00 - 事故关闭

关键:精确到分钟,包含所有尝试过的操作。

复盘会议

参会人员

  • IC(事故指挥官)
  • TL(技术负责人)
  • 相关工程师
  • 可选:产品经理、客户支持代表

会议流程(1 小时)

  1. 时间线回顾(15 分钟)

    • 由 IC 带领,按时间线回顾
    • 补充遗漏的细节
  2. 五个为什么(5 Whys)(20 分钟)

    • 找出根本原因
    • 不只停留在表面
  3. 改进项讨论(20 分钟)

    • 列出所有可改进的点
    • 分配责任人和 deadline
  4. 总结(5 分钟)

    • 确认 action items
    • 感谢团队的努力

五个为什么示例

问题:数据库连接池耗尽

为什么连接池耗尽?
→ 连接没有正确释放

为什么没有释放?
→ 代码里有连接泄漏

为什么代码有泄漏?
→ 新功能没有正确关闭连接

为什么没有发现?
→ 测试环境数据量小,没有触发

为什么没有监控?
→ 缺少连接池使用率监控

根因:
1. 代码缺陷:连接未正确释放
2. 测试不足:没有大流量测试
3. 监控缺失:缺少连接池监控

事故报告模板

# 事故报告:Payment API Outage

## 基本信息
- 事故 ID:INC-2026-0315-001
- 发生时间:2026-03-15 14:23 UTC
- 恢复时间:2026-03-15 14:45 UTC
- 总时长:22 分钟
- 严重级别:P1

## 影响评估
- 受影响用户:约 8000 用户
- 失败支付:约 5000 笔
- 收入影响:约 ¥200,000
- 数据丢失:无

## 时间线
[详细时间线...]

## 根因分析
[五个为什么...]

## 事故经过
[详细描述发生了什么...]

## 响应评价
做得好的:
- 快速定位问题(10 分钟)
- 有效止损(扩容)

做得不好的:
- 监控报警太晚(错误率 1% 才报警,应该 0.5%)
- 缺少连接池监控

## 改进项

| 改进项 | 负责人 | 优先级 | Deadline | 状态 |
|--------|--------|--------|----------|------|
| 修复连接泄漏 | 张三 | P0 | 3-17 | 待完成 |
| 添加连接池监控 | 李四 | P0 | 3-17 | 待完成 |
| 优化报警阈值 | 王五 | P1 | 3-20 | 待完成 |
| 增加大流量测试 | 赵六 | P1 | 3-31 | 待完成 |

## 经验教训
[总结学到的经验...]

## 附件
- 相关日志:[link]
- 监控截图:[link]
- 复盘会议录屏:[link]

改进项跟踪

关键:复盘的价值在于改进,而不是报告。

跟踪机制

  • 所有 action items 进入 backlog
  • 每周 review 进度
  • 事故后 1 个月验证改进效果

文化建设

Blameless Culture(无责文化)

核心

  • 人都会犯错
  • 系统设计应该防错
  • 追责只会让人隐瞒问题

实践

  • 复盘时不问「谁做错了」
  • 而是问「系统设计出了什么问题」
  • 公开表扬主动上报问题的人

心理安全

On-call 不应该是恐惧的来源。

建立心理安全

  • 新成员 on-call 前 pairing 资深工程师
  • 明确「不懂就问」是 expected
  • 事故后感谢而不是指责
  • 定期轮岗,避免 burnout

持续学习

建立事故知识库

  • 所有事故报告归档
  • 可搜索、可学习
  • 新成员 onboarding 必读

定期分享

  • 每月「事故学习会」
  • 分享有趣的事故案例
  • 讨论预防方案

工具推荐

类别工具用途
监控Datadog, Grafana指标可视化
报警PagerDuty, OpsgenieOn-Call 管理
日志ELK, Splunk日志聚合分析
链路追踪Jaeger, Zipkin分布式追踪
事故管理Incident.io, PagerDuty事故响应流程
沟通Slack实时沟通
文档Notion, ConfluenceRunbook, 事故报告

总结

事故响应体系 = 80% 准备 + 15% 执行 + 5% 复盘

立即行动清单

本周

  • 检查你的监控是否覆盖业务层
  • 为 Top 3 服务写 Runbook
  • 确认 on-call 轮换和补偿机制

本月

  • 做一次桌面演练
  • 建立事故响应流程文档
  • 创建事故报告模板

本季度

  • 做一次功能演练
  • 复盘最近 3 起事故
  • 更新所有 Runbook

关键原则

  1. 事前准备 > 事中救火:花 80% 时间准备
  2. 先止损,再诊断:保护用户和业务
  3. Blameless:从系统角度改进,不追责个人
  4. 持续演练:没有演练的体系不可靠
  5. 学习成长:每次事故都是改进机会

参考资源

书籍

  • 《Site Reliability Engineering》Google
  • 《The DevOps Handbook》
  • 《Chaos Engineering》

文章

工具文档

  • PagerDuty On-Call Guide
  • Datadog SLO Monitoring
  • Kubernetes Troubleshooting

你印象最深的一次生产事故是什么?从中学到了什么?

本文总结自我 5 年处理 100+ 起事故的实战经验。希望这些经验能帮你从容应对下一个凌晨 3 点的报警。

---

评论