容灾断网演练核心是验证副本集在网络分区下的数据一致性与服务可用性;必须禁用chainingallowed、显式设置priority和votes以防双主;需确认多数派健康、oplog同步正常,并配合读偏好与writeconcern测试写入响应。

容灾断网演练不是“看看集群会不会挂”,而是验证你的副本集在真实网络分区下能否维持数据一致性和服务可用性。关键结论:必须提前禁用 chainingAllowed、显式设置 priority 和 votes,否则断网后极大概率出现双主(split-brain)——这是 MongoDB 最危险的状态,会导致写覆盖和数据丢失。
断网前必须关闭链式复制
默认开启的 chainingAllowed: true 允许 Secondary 从其他 Secondary 同步 oplog,看似节省主节点带宽,但在跨机房或断网场景下会放大延迟、混淆心跳路径,导致选举混乱。一旦网络分区发生,B 机房节点可能从 A 机房已失联的 Secondary 拉取旧 oplog,进而误判主节点状态并发起错误选举。
- 检查当前配置:
rs.conf().settings.chainingAllowed,若返回true,必须修改 - 执行更新:
rs.reconfig({ _id: "rs0", version: rs.conf().version + 1, settings: { chainingAllowed: false } }, { force: true }) - 该操作无需重启,但需确保所有节点已同步新配置(
rs.status().members[n].lastHeartbeatRecv时间差
用 iptables 模拟精准断网,别只 kill 进程
单纯 docker stop 或 kill -9 mongod 只模拟节点宕机,无法触发网络分区特有的脑裂风险。真实容灾场景中,机器还在跑、进程还活着,只是彼此收不到心跳包。
- 在目标容器内执行(以断开 mongodb1 对 mongodb0 的连接为例):
iptables -A OUTPUT -d 172.20.0.2 -j DROP(假设 mongodb0 IP 是 172.20.0.2) - 验证是否生效:
ping 172.20.0.2应超时;telnet 172.20.0.2 27017应拒绝连接 - 恢复命令:
iptables -D OUTPUT -d 172.20.0.2 -j DROP - 注意:不要用
ufw或宿主机防火墙,它可能影响 Docker 网络桥接,导致结果不可控
断网后立刻验证三件事,而不是等 30 秒看 rs.status()
选举不是瞬间完成的,但错误信号会在 10 秒内暴露。别等 rs.status() 返回稳定状态,先盯住这些实时指标:
- 检查是否双主:
db.adminCommand({ replSetGetStatus: 1 }).members.filter(m => m.stateStr === "PRIMARY").length—— 结果必须恒为 1 - 确认多数派仍在运行:
db.adminCommand({ replSetGetStatus: 1 }).ok应为 1,且members[n].health为 1 的节点数 ≥ ⌈N/2⌉+1(例如 3 节点需至少 2 个健康) - 查 oplog 同步断点:
rs.printSecondaryReplicationInfo()中maxLagSecs若持续 > 30,说明某节点已脱离同步流,可能是链式复制残留或投票权配置错误
最常被忽略的点是:断网演练必须配合读偏好测试。即使选举成功,如果应用仍向已失联的 Primary 发起写请求(因 DNS 缓存或连接池未刷新),w:majority 会卡死或降级失败。你得用真实客户端连上去发几条带 writeConcern: { w: "majority", wtimeout: 2000 } 的写入,看它是否在 2 秒内明确报错,而不是无限 hang 住。











