一次演练被判定"成功":主库切到备库用了 40 秒,业务在 90 秒后恢复。复盘时有人问了一句"演练期间真实流量跑在哪",答案是没有真实流量——演练在独立的预发环境做,用的是造出来的数据。于是这次"成功"验证的只是"脚本能跑通",而不是"故障时能不能兜住"。
演练的价值不在"有没有做",而在它是否触及了真实系统的约束。隔离环境、造数据、只测happy path,这三件事任何一件成立,演练的结论就要打折。
1. 演练的四个真实性维度
| 维度 | 问题 |
|---|---|
| 流量真实性 | 有真实请求在跑吗 |
| 数据真实性 | 数据量与分布接近生产吗 |
| 依赖真实性 | 上下游是真实的还是桩 |
| 人员真实性 | 是值班的人在做,还是准备过的人 |
四个维度可以组合成一张"真实性分数",用来横向比较不同演练的信息量:流量真、数据真、依赖真、人员普通四项各算一分。分数低的演练不是白做,但它的结论只能支撑很窄的决定。
第四项最容易被忽略:演练常常由"最熟悉这套系统的人"执行,而真实故障发生在凌晨、由不熟悉的人处置。演练测出的时长,往往比真实情况乐观一倍以上。
2. 四档演练的代价与收益
| 档位 | 做法 | 能验证 |
|---|---|---|
| 桌面推演 | 只讨论流程 | 分工与决策路径 |
| 隔离环境演练 | 独立环境跑脚本 | 脚本与工具可用 |
| 影子/只读演练 | 生产只读侧演练 | 观测与告警链路 |
| 生产灰度演练 | 小比例真实流量 | 端到端可用性 |
四档之间是"信息量"的阶梯,不是"要不要认真"的阶梯:低档演练做扎实也有价值,因为它验证的是分工与沟通;而高档演练若准备草率,反而会制造事故。
第三档是性价比拐点:在生产上做只读或小比例的真实演练,比在隔离环境做全流程演练更有信息量。代价是需要更强的熔断与回滚保障。
还有一个成本维度值得算:演练本身的代价。它占用工程与业务时间、承担轻微风险、可能引发真实告警。所以"做一次"这件事必须有明确要回答的问题——没有问题,它只是仪式。
3. 演练该验证的五件事
| 目标 | 判据 |
|---|---|
| 发现能力 | 告警在多长时间内触发 |
| 定位能力 | 从告警到定位到组件用了多久 |
| 处置能力 | 切换/回滚动作能否按预期执行 |
| 恢复判据 | 什么现象说明"恢复了" |
| 沟通链路 | 谁通知谁、多久一次 |
恢复判据要写成可观测的条件,而不是"看起来正常":
// 恢复判据:三档,逐档确认
L1 技术恢复:主库可写、复制延迟 < 1s、连接数回落至基线
L2 业务恢复:错误率 < 0.1%、下单成功率回到基线 ±5%
L3 用户体验恢复:客服工单量回落到日常水平
// 三档都满足才算"恢复";只满足 L1 时说"技术上恢复",不说"恢复"
第四项最常缺失:很多演练在"动作执行完"就宣布结束,而没有定义"什么时候算恢复"。结果真实故障里,团队在动作做完后仍不知道该不该继续观察。
4. 让演练不伤生产的三道保险
| 保险 | 作用 |
|---|---|
| 明确的熔断条件 | 指标恶化到阈值立即终止 |
| 可回滚的每一步 | 任何一步都能撤回 |
| 有人专职踩刹车 | 有人只负责看指标 |
踩刹车的人还需要一个"提前终止"的判据:不是等到指标恶化才停,而是在"看起来要恶化"时停。演练的价值不高于一次真实故障的代价。
第三项是组织要求:执行演练的人不能同时负责判断"要不要停",因为他正忙于操作。必须有一个只看指标、有权叫停的人。
// 演练单的三项前置
abort_if: // 熔断条件,先写后做
- error_rate > 1%
- p99 > 2 × baseline
- 任一 P1 告警
rollback: "bin/switch.sh --to blue && bin/verify.sh"
brake_owner: "李四(只看指标,不参与操作)"
演练还要考虑"谁来观摩":让不参与执行的相邻团队旁听,往往能发现沟通断点。执行者自己很难察觉"我没通知到谁",因为在他的视角里那就是全部。
// 演练角色的最小集合
执行人:按单操作(1–2 人)
踩刹车:只看指标,有权终止(1 人)
观察员:相邻团队代表,记录沟通断点(1 人)
记录员:时间线,精确到分钟(可由观察员兼任)
5. 演练结论怎么写才有用
| 写法 | 价值 |
|---|---|
| "演练成功" | 几乎为零 |
| "切换耗时 40 秒,业务中断 90 秒" | 中 |
| 上一条 + "本次未覆盖:真实流量、跨机房、夜间人手" | 高 |
| 上一条 + "下次演练要补的三项" | 最高 |
第三行的"未覆盖"是结论的主体:它告诉读者这次结论的适用范围。没有它,"成功"会被当成"这类故障我们都能扛"。
// 演练结论:以"未覆盖"为主体的写法
drill: db-failover
result:
measured: { switch: 40s, recovery: 90s }
covered: [主库不可用, 备库切换脚本, 告警触发]
not_covered: [真实流量, 跨机房延迟, 夜间值班人手]
conclusion: "脚本可用;可用性结论不成立,需生产灰度演练后再评估"
next:
- "生产只读侧演练,验证真实流量下的表现"
- "补一次夜间时段的桌面推演"
演练的时间选择也是真实性的一部分:总在下午做的演练,永远测不出夜间的人力约束。合理做法是把一部分演练放在非工作时段,哪怕只做桌面推演。
// 演练排期:按时间维度覆盖
每季度 1 次生产灰度演练(低峰,真实流量)
每季度 1 次夜间桌面推演(验证人员与升级链路)
每年 1 次跨机房/跨区域演练(依赖真实性)
6. 排错:五种"演练通过但故障时不行"
| 现象 | 成因 | 处理方向 |
|---|---|---|
| 演练顺利、真实故障混乱 | 执行人是熟手 | 换成值班的人做 |
| 切换成功但业务没恢复 | 未定义恢复判据 | 演练单加"恢复判据"栏 |
| 演练中出了新故障 | 无熔断条件 | 先写 abort_if |
| 数据量太小看不出问题 | 造数据 | 用生产数据脱敏或影子 |
| 每次演练结论都一样 | 只测同一路径 | 换故障场景 |
演练的场景设计要有"难度阶梯":从单点故障到组合故障。单组件挂掉是第一级,组件挂掉 + 流量翻倍是第二级,再加上值班人手不足是第三级。多数团队的演练长期停在第一级。
第五项说明演练在"重复确认已知事实":如果连续三次演练都没有发现新问题,说明场景设计已经失效,该换更苛刻的场景,而不是继续做同样的。
7. 边界:什么情况不必做高保真演练
| 场景 | 为什么 | 做法 |
|---|---|---|
| 单实例、无高可用设计 | 无切换可演 | 只做恢复演练 |
| 影响面极小的内部系统 | 代价高于收益 | 桌面推演 |
| 已有真实故障复盘可参考 | 信息已获得 | 用复盘代替 |
| 演练成本超过预期损失 | 不划算 | 明确接受风险 |
还有一条与节奏有关的边界:演练频率不必与系统规模成正比,但与变更频率相关。系统改得多,故障模式就变,演练该跟上;半年没改动的系统,重复演练同一场景的信息量接近零。
判断口径一句话:这次演练的结论会被用来支撑什么决定。只支撑"脚本能跑",隔离环境就够;支撑"能不能扛住故障",就必须有真实流量。
8. 自测
- 演练的四个真实性维度中,哪一个最容易被忽略?为什么它会让时长结论系统性偏乐观?
- 四档演练里,哪一档是性价比拐点?它需要什么额外保障?
- 五个验证目标中,哪一项最常缺失?缺失会导致真实故障中出现什么问题?
- 为什么"执行演练的人"不能同时负责"判断要不要停"?
- 演练结论里"未覆盖"为什么是主体?没有它会怎么被误用?
- 连续三次演练都没有新发现,说明什么?该怎么调整?