Skip to main content

应急响应:Runbook 与故障复盘

出事时按图索骥 = 应急响应。没 Runbook 的人,事故时会慌;慌了 = 二次故障

一、避坑指南

  1. Runbook 必须写,写了才能不慌

    • ❌ 故障时全靠脑子回忆
    • ✅ 每个核心服务都有「出问题了怎么办」手册
  2. 响应速度 > 根因

    • 5 分钟内先止损(回滚 / 关闭功能 / 限流)
    • 根因后面再查
    • 带着事故查根因 = 拖延止损
  3. 不要在事故中改方案

    • ❌ 故障时改架构、重构、加监控
    • ✅ 故障时只止血
  4. 复盘要无指责(blameless)

    • ❌ 「这谁写的代码」
    • ✅ 「我们系统的什么机制没防住这个错误」
  5. 安全事件优先级最高

    • 数据泄露、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
XSSP1修 + 全站扫描 + 通报
弱口令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%。任一步异常立即回滚

十、相关文档