Docker Compose 快速拉起三节点 MongoDB 副本集需确保:统一镜像版本(如 mongo:6.0.18)、显式指定相同 --replSet 名、各节点 hostname 可互相解析、独立 volume 挂载 /data/db、初始化后验证 rs.status().myState === 1。

生产环境的 MongoDB 副本集必须做故障演练,但不能直接在真实集群上 kill -9 或断网——这会触发非预期的选举震荡、回滚甚至数据不一致。真正安全可控的方式,是用 Docker Compose 搭建与生产配置一致的本地副本集,并通过 docker network disconnect、tc(traffic control)等工具模拟网络分区、延迟、丢包等中间态故障。
怎么用 Docker Compose 快速拉起三节点副本集?
关键不是“能跑”,而是配置要和生产对齐:版本号、启动参数、replSet 名、oplogSize、storage.engine 都得一致。否则演练结果不可信。
- 所有节点必须使用相同 MongoDB 版本镜像,比如
mongo:6.0.18,避免因版本差异导致选举逻辑或心跳超时行为不同 -
mongod启动命令中必须显式指定--replSet rstl(替换为你的实际 replSet 名),且三个节点 host 名需可互相解析(Docker Compose 默认提供 DNS 服务) - 在
docker-compose.yml中为每个服务配置独立 volume,避免容器重启后数据丢失;同时挂载/data/db而非仅/data,防止 journal 目录路径错位 - 初始化脚本里调用
rs.initiate()后,必须等待rs.status().myState === 1才算 PRIMARY 就绪,否则后续写入会失败
如何精准模拟网络分区而非简单断网?
直接 docker network disconnect 会彻底切断通信,但真实故障往往是单向延迟或部分丢包。要用 tc 控制流量,才能暴露客户端重试逻辑、驱动超时、连接池耗尽等真实问题。
- 进入容器执行:
tc qdisc add dev eth0 root netem delay 2000ms 500ms distribution normal,模拟北京-上海跨机房延迟抖动 - 丢包测试:
tc qdisc add dev eth0 root netem loss 15%,观察 driver 是否触发重连、是否 fallback 到其他 secondary - 只限某两个节点间故障(如 primary ↔ secondary1 断连,但 secondary1 ↔ secondary2 正常):需用
tc在对应容器内分别配置,不能全局断网 - 恢复时用
tc qdisc del dev eth0 root,而不是重启容器——这样才能验证 oplog 追同步是否正常,而非靠 initial sync 重灌全量
演练时 client 端最容易忽略的配置点
很多故障现象其实不是 MongoDB 本身的问题,而是 driver 或应用层没配对。比如明明 secondary 可读,但查询始终打到已失联的 primary 上。
-
readPreference=secondaryPreferred不等于“一定走 secondary”——如果 primary 仍响应心跳(哪怕写失败),driver 仍可能把读请求发过去,导致超时堆积 - 必须设置
serverSelectionTimeoutMS=3000和heartbeatFrequencyMS=10000,否则默认 30s 超时太长,掩盖了快速故障感知能力 - Java 驱动下,
maxWaitTime和maxConnectionLifeTime若设得太小,会在网络抖动时频繁重建连接,压垮 connection pool - 验证时别只看
rs.status(),更要抓 client 日志里的TopologyDescriptionChangedEvent和ConnectionPoolCreatedEvent,确认 driver 是否真感知到了 topology 变化
最危险的盲区是:以为“选举成功 = 服务恢复”。实际上,新 primary 上任后,旧 primary 如果网络恢复但尚未完成 rollback,它可能短暂处于 ROLLBACK 状态——此时若 client 还连着它,写操作会被拒绝,但错误码可能是 NotPrimaryNoSecondaryOk 而非明确提示 rollback,容易被日志过滤掉。











