应急响应:Runbook 与故障复盘
出事时按图索骥 = 应急响应。没 Runbook 的人,事故时会慌;慌了 = 二次故障。
一、避坑指南
Runbook 必须写,写了才能不慌:
- ❌ 故障时全靠脑子回忆
- ✅ 每个核心服务都有「出问题了怎么办」手册
响应速度 > 根因:
- 5 分钟内先止损(回滚 / 关闭功能 / 限流)
- 根因后面再查
- 带着事故查根因 = 拖延止损
不要在事故中改方案:
- ❌ 故障时改架构、重构、加监控
- ✅ 故障时只止血
复盘要无指责(blameless):
- ❌ 「这谁写的代码」
- ✅ 「我们系统的什么机制没防住这个错误」
安全事件优先级最高:
- 数据泄露、SQL 注入、CC 攻击 = P0
- 业务出错也靠后
二、故障分级
| 等级 | 影响范围 | 响应时间 | 处置权限 |
|---|---|---|---|
| P0 | 全平台不可用(登录、支付、主流程) | 5 分钟 | 全员 + 主管 |
| P1 | 大面积影响(>30% 用户报错) | 15 分钟 | on-call + 主管 |
| P2 | 部分影响(10%~30% 用户) | 30 分钟 | on-call |
| P3 | 边缘功能(< 10% 用户) | 4 小时 | 业务开发 |
| P4 | 体验问题(不影响主流程) | 当天 | 业务开发 |
三、应急 SOP(标准流程)
3.1 事故响应 5 步法
1. 发现(告警 / 用户反馈)
↓
2. 确认(看监控 / 日志判断真假阳性)
↓
3. 止损(回滚 / 切流量 / 关闭功能) ← 关键!5 分钟内必须
↓
4. 恢复(确认服务恢复 + 用户可用)
↓
5. 复盘(post-mortem 文档,48 小时内)
3.2 第一响应人 On-call 动作清单
## P0/P1 事故响应清单(5 分钟内完成)
- [ ] 1. 看到告警 → 钉钉群同步「正在处理」
- [ ] 2. 打开监控面板(Prometheus / Grafana)
- [ ] 3. 打开日志(ELK / Loki)搜索最近 5 分钟异常
- [ ] 4. 确认是「真事故」还是「测试 / 误报」
- [ ] 5. 真事故:立即止损
- [ ] a) 最近 10 分钟有发布?→ 回滚
- [ ] b) 流量异常?→ 限流 / 切流量
- [ ] c) 依赖服务挂了?→ 切降级方案
- [ ] d) 数据库挂了?→ 切读备库
- [ ] 6. 通知主管(>P0 自动电话)
- [ ] 7. 拉战时群(事故 channel)
- [ ] 8. 每 10 分钟在群内同步进展
- [ ] 9. 服务恢复 → 监控无异常 30 分钟
- [ ] 10. 关闭事故、发状态页「已恢复」
四、Runbook 模板
每个核心服务都应该有一份 Runbook。
# 服务名:my-web(SSR 应用)
## 基础信息
- 负责人: @张三 @李四
- 技术栈: Next.js 15 + Node 20
- 部署: K8s 集群 prod-cluster
- 镜像: ghcr.io/myorg/my-web
- 监控: Grafana https://grafana.example.com/d/my-web
- 日志: Loki https://loki.example.com
## 关键依赖
- 数据库: postgres-prod (10.61.5.12:5432)
- Redis: redis-prod (10.61.5.13:6379)
- 第三方 API: 微信支付、阿里云短信
## 常见故障与处置
### 故障 1: 502 Bad Gateway 激增
**症状**: 错误率 > 5%, 用户报「页面打不开」
**可能原因**:
- Node 进程 OOM(看 `kubectl describe pod`)
- 数据库连接池耗尽(看应用日志 `connection pool timeout`)
- 第三方 API 超时(看接口耗时)
**处置步骤**:
1. 看 `kubectl top pod` 找最吃资源的 Pod
2. 看应用日志(`kubectl logs my-web-xxx | grep -i error`)
3. 如 OOM:`kubectl rollout restart deployment/my-web`
4. 如数据库:检查连接数(`SELECT count(*) FROM pg_stat_activity`)
5. 如第三方:开启降级(开关: `feature.thirdPartyApi = false`)
### 故障 2: 接口响应慢(>3s)
**症状**: P95 > 3s,告警触发
**处置**:
1. 看 APM trace 找最慢的 span
2. 看慢 SQL(开启 `pg_stat_statements`)
3. 看缓存命中率(Redis info)
### 故障 3: 发布后异常
**症状**: 发布时间点之后错误率上升
**处置**:
1. `kubectl rollout undo deployment/my-web` ← **回滚**
2. 通知:版本回滚到 v1.2.2
3. 保留异常 Pod 做调试:`kubectl set env deployment/my-web DEBUG=true`
## 联系信息
- 主管: 张三 138-xxxx
- DBA: 李四 139-xxxx
- 运维: 王五 137-xxxx
- 第三方: 阿里云工单 95187
五、限流 / 熔断 / 降级
三件套:出问题时的兜底机制。
5.1 限流(Rate Limit)
// 用 express-rate-limit
import rateLimit from "express-rate-limit";
const limiter = rateLimit({
windowMs: 60 * 1000, // 1 分钟
max: 100, // 最多 100 次
message: "Too many requests",
standardHeaders: true,
});
app.use("/api/", limiter);
Nginx 限流(兜底):
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
server {
location /api/ {
limit_req zone=api burst=20 nodelay;
limit_req_status 429;
}
}
5.2 熔断(Circuit Breaker)
// 用 opossum
import CircuitBreaker from "opossum";
const breaker = new CircuitBreaker(callThirdPartyApi, {
timeout: 3000, // 3s 超时
errorThresholdPercentage: 50, // 50% 错误触发熔断
resetTimeout: 30000, // 30s 后尝试恢复
});
breaker.fallback(() => ({ data: "default" })); // 降级返回
5.3 降级(Degradation)
// 功能开关 / 降级开关
const features = {
recommendation: true, // 推荐服务
comment: true, // 评论
search: true, // 搜索
};
app.get("/api/recommend", (req, res) => {
if (!features.recommendation) {
return res.json({ items: [] }); // 返回空列表
}
// 正常逻辑
});
降级原则:优先保住主流程(登录、支付),砍掉非主流程(推荐、广告)。
六、灰度发布与回滚
6.1 灰度策略
| 策略 | 比例 | 适用 |
|---|---|---|
| 金丝雀 | 1%~5% | 重大变更验证 |
| 小流量 | 10% | A/B 测试 |
| 大流量 | 50% | 高风险版本过渡 |
| 全量 | 100% | 稳定版本 |
6.2 一键回滚
# Docker Compose
docker compose pull web && docker compose up -d web
# PM2
pm2 reload ecosystem.config.js --env production
# K8s
kubectl rollout undo deployment/my-web
# Vercel
vercel rollback # 仪表盘点一下也行
七、Post-mortem 复盘文档
# 事故复盘:2026-07-09 支付失败率飙升
## 事故概要
- 时间: 2026-07-09 14:30 ~ 15:20(50 分钟)
- 等级: P0
- 影响: 约 5000 笔订单支付失败
- 根因: 微信支付 API 限流,未及时降级
## 时间线
- 14:25 - 同事小王发布 v2.1.0(增加推荐商品弹窗)
- 14:30 - 告警:支付失败率 5% → 8% → 12%
- 14:32 - on-call 张三确认事故
- 14:35 - 尝试重启服务,无效
- 14:40 - 发现:微信支付 API 限流(错误码 429)
- 14:45 - 启动降级:暂时关闭推荐弹窗(释放了微信支付调用)
- 15:20 - 微信支付 API 恢复
- 15:30 - 监控正常,关闭事故
## 根因分析
- **直接原因**: 微信支付 API 限流
- **根本原因**: 推荐弹窗在支付前预加载,调了 3 次微信支付(埋雷)
- **系统问题**: 没限流 + 没熔断 + 没降级开关
## 改进措施
| 改进项 | 负责人 | 截止日期 |
| --- | --- | --- |
| 加微信支付限流(10 QPS) | 张三 | 7/12 |
| 加熔断器 | 李四 | 7/15 |
| 推荐弹窗去掉支付预加载 | 王五 | 7/11 |
| 添加「推荐服务降级开关」Runbook | 张三 | 7/10 |
| 灰度发布流程(先 1% 再全量) | 主管 | 7/20 |
## 经验教训
- 永远不要在支付链路加额外调用
- 第三方 API 必须限流 + 熔断
- 大版本发布必须灰度
复盘原则(blameless):
- ✅ 「我们系统没防住这个错误」
- ❌ 「这是小王的锅」
- 目标:让系统更难出错,不是找人背锅
八、安全事件响应
8.1 常见安全事件
| 事件 | 紧急度 | 处置 |
|---|---|---|
| 数据泄露 | P0 | 立即下架、报警、通知用户、合规上报 |
| SQL 注入 | P0 | 紧急修复 + 复盘所有类似接口 |
| CC 攻击 | P1 | 启用 WAF / 限流 / 切高防 IP |
| XSS | P1 | 修 + 全站扫描 + 通报 |
| 弱口令 | P2 | 强制改密 + 加 2FA |
8.2 数据泄露应急 SOP
1. 立即下架相关服务
2. 评估泄露范围(影响多少用户、什么字段)
3. 通知:
- 公司安全团队 + 法务 + 主管
- 用户(72 小时内,《个人信息保护法》要求)
- 监管机构(重大事件)
4. 修复漏洞
5. 提供用户补偿(如改密、监控、身份保护)
6. 复盘 + 改进
九、面试高频
Q1:事故响应 5 步法?
A:发现 → 确认 → 止损(关键,5 分钟内)→ 恢复 → 复盘。先止损再查根因。
Q2:Runbook 是什么?为什么需要?
A:每个核心服务的「出问题了怎么办」手册。含:负责人、监控入口、常见故障、处置步骤、联系信息。事故时按图索骥,不慌。
Q3:限流 / 熔断 / 降级区别?
A:
- 限流:请求太多 → 拒绝一部分
- 熔断:依赖服务挂 → 自动切断一段时间
- 降级:核心服务保主流程,砍非主流程
Q4:怎么写一份好的 post-mortem?
A:blameless(无指责)原则 + 5 段式:概要 / 时间线 / 根因 / 改进措施 / 经验教训。重点是「让系统更难出错」不是「找人背锅」。
Q5:金丝雀发布怎么做?
A:1%~5% 流量先跑新版本 → 监控无异常 → 逐步扩到 10%、50%、100%。任一步异常立即回滚。