3. 故障演练方案设计
故障演练方案不是一份“演练通知”,而是一份把风险边界、注入手段、影响判断、退出条件和授权链条写清楚的工程文档。方案设计得越具体,演练时越不容易失控;反之,如果只写“对副本集做一次主节点切换演练”,执行人会在真实环境里临时决定切哪个节点、切多久、失败怎么办,风险就不可控了。
本节围绕五个要素展开:演练范围、故障注入方式、影响评估、回滚预案与审批流程。它们不是并列的五个章节,而是一条从“划定边界”到“获得授权”的决策链:范围决定能碰什么,注入方式决定怎么碰,影响评估决定碰了会怎样,回滚预案决定碰坏了怎么退,审批流程决定谁有权批准这次“碰”。
一、演练范围:先划边界,再谈动作
范围要落到具体对象和具体维度上。对象维度包括集群、副本集、分片、节点角色、数据库、集合、索引、连接串、驱动版本;环境维度包括生产、预发、灰度、灾备;时间维度包括演练窗口、业务低峰期、可占用时长。一个可执行的范围描述应当像这样:
演练对象:订单库 MongoDB 副本集 order-rs(3 节点,主节点 order-rs-01)
演练环境:生产环境(灰度流量已切至备用集群)
演练窗口:周六 02:00–04:00,最长占用 90 分钟
允许操作:主节点强制切换、单节点进程 kill、网络延迟注入(≤200ms)
禁止操作:删除数据文件、修改副本集配置版本、对分片键做变更
范围里最容易被忽略的是“禁止操作”。明确写出不能做什么,比只写能做什么更能防止执行人越界。同时要标注业务归属:哪些业务线在演练窗口内仍会读写该集群,是否需要提前降级或切流。
二、故障注入方式:按“真实故障”选手段
注入方式要与想验证的能力对应。常见手段包括:
- 进程级:kill -9 mongod,验证副本集自动选主与驱动重连;
- 网络级:用 tc/netem 注入延迟、丢包或分区,验证心跳超时与多数派写入行为;
- 资源级:限制 CPU、内存或磁盘 IO,验证慢查询与连接堆积;
- 配置级:临时调整 electionTimeoutMillis、writeConcern,验证参数变化对可用性的影响;
- 数据级:在影子集合上模拟误删或脏数据,验证备份恢复与回滚脚本。
选择注入方式时,要区分“可逆”与“不可逆”。kill 进程、网络延迟、资源限制都是可逆的;删除数据文件、修改分片元数据则不可逆,除非有备份。演练方案中应优先使用可逆手段,不可逆手段必须放在有备份且经过验证的前提下。
三、影响评估:把“可能出问题”量化
影响评估要回答三个问题:影响谁、影响多久、影响多大。可以从以下维度展开:
| 维度 | 评估内容 | 示例判断 |
|---|---|---|
| 可用性 | 主节点切换期间写入是否中断 | 预计 10–30 秒写入失败,读可继续 |
| 一致性 | 是否可能读到回滚数据 | w:majority 下无回滚;w:1 下可能丢最近写入 |
| 性能 | 切换后新主节点能否承接流量 | 新主节点 CPU 余量需 ≥40% |
| 业务 | 哪些接口会报错、是否可重试 | 下单接口需幂等重试,查询接口可降级 |
| 数据 | 是否存在不可恢复的数据损失 | 本次不涉及数据删除,风险低 |
影响评估的结论要写成可观测的判据,例如“若 5 分钟内未完成选主,或复制延迟持续大于 60 秒,则判定为异常,触发回滚”。判据越明确,执行人越不需要临场发挥。
四、回滚预案:不是“再切回去”这么简单
回滚预案要针对每一种注入方式给出退出路径。以主节点切换为例,回滚不是简单地把原主节点切回来,而要考虑:原主节点是否还能加入副本集、数据是否落后、是否需要先同步再提升。一个可操作的回滚预案应包含:
- 触发条件:选主超时、业务错误率超过阈值、复制延迟不可收敛;
- 回滚动作:停止注入 → 检查节点状态 → 必要时强制重新配置 → 恢复原主节点角色;
- 验证动作:确认主节点唯一、复制正常、业务写入恢复;
- 时间上限:回滚必须在演练窗口内完成,超时则升级处理。
五、审批流程:谁批准、批什么、留什么痕
审批流程的核心是“分级授权”。低风险演练(如预发环境单节点重启)可由技术负责人批准;高风险演练(如生产主节点强制切换)需要业务负责人、DBA 负责人和值班经理共同确认。审批内容至少包括:演练范围、注入方式、影响评估结论、回滚预案、演练窗口和回滚决策人。
审批不是走形式,而是把责任和决策权绑定到具体的人。方案中应明确现场指挥、操作执行、业务观察和回滚决策四个角色,避免出现“谁都能喊停、谁都不敢喊停”的局面。
把上述五个要素写进同一份方案后,还需要做一次“桌面推演”:由执行人逐条复述操作步骤,由业务观察人确认监控看板,由回滚决策人确认触发条件。推演中发现的任何模糊点,都应回到方案里改成明确动作。方案定稿后,演练当天只做两件事:按方案执行,按判据决策。这样,演练才是一次可控的验证,而不是一次冒险。