默认配置下副本集可能脑裂,因网络分区时多数派失联会各自选主;预防关键是确保任意单点故障后剩余节点数≥⌊N/2⌋+1,并配齐writeConcern: {w: "majority"}与readConcern: "majority"。

为什么默认配置下副本集仍可能脑裂
脑裂不是配置错误导致的异常,而是网络分区发生时副本集的正常反应——只要多数派节点彼此失联,各自就可能选出一个 PRIMARY。关键在于:MongoDB 的选举机制本身不阻止双主,它只保证“多数派内只有一个主”。所以预防脑裂,本质是预防“多数派被拆散”或“少数派也能写”。
常见误判点:rs.status() 显示两个 "stateStr": "PRIMARY" 时,不是系统坏了,而是网络已断开;heartbeatTimeoutSecs 调小不会防脑裂,反而更容易触发假选举。
- 三节点集群中,若两个节点在同一机房、一个在异地,该机房整体断电就会立刻脑裂(剩下1个节点无法形成多数)
- 配置了
"votes": 2或意外启用多个仲裁节点,会导致票数分布失衡,让少数派获得选举权 - 没开
storage.journal.enabled,即使写入满足w: "majority",崩溃后仍会回滚——看起来“防住了”,实则数据已不可靠
跨数据中心部署必须满足多数派存活条件
地理分散不是越多越好,而是要确保任意单点故障后,剩余节点数仍 ≥ ⌊N/2⌋+1。否则,分区即脑裂。
- 三节点:必须 1-1-1 分布在三个独立可用区(或数据中心),不能 2-1;2-1 布局下,2 节点所在中心故障,剩下 1 节点只能降级为
SECONDARY,整个集不可写 - 五节点:推荐 2-2-1,而非 3-2;后者在 3 节点中心故障时只剩 2,无法构成多数(5 节点需至少 3 票)
- 严禁给
shard副本集加arbiterOnly节点:仲裁节点不存数据,却占一票,会稀释数据节点的容灾能力
writeConcern 和 readConcern 必须成对启用
单靠选举机制无法防脑裂后果,真正兜底的是客户端写入和读取行为约束。不配齐二者,等于裸奔。
- 所有写操作必须显式指定
writeConcern: {w: "majority"},禁用默认w: 1;否则脑裂时少数派PRIMARY会静默接受写入,且不报错 - 配套设置
readConcern: "majority";否则即使连到假主,find()仍可能返回未同步的数据 - Java 驱动需设
heartbeatFrequencyMS=5000并监听ServerDescriptionChangedEvent,Node.js 驱动应启用directConnection=false,避免缓存失效节点
journal 和 writeConcernMajorityJournalDefault 是最后一道防线
即使多数节点都落盘了,若其中部分节点没开启 journal,MongoDB 仍认为满足 w: "majority",但这些节点重启后 oplog 丢失,已确认写入会被回滚——用户看到“写成功”,实际数据已分裂。
- 检查每个节点:运行
db.runCommand({ getCmdLineOpts: 1 }),确认storage.journal.enabled为true - 检查副本集全局设置:执行
db.adminCommand({ getParameter: 1, writeConcernMajorityJournalDefault: 1 }),返回值必须是true - 若为
false,必须在启动参数中显式添加--journal并重启节点;仅靠rs.reconfig()无法动态开启
最容易被忽略的点:恢复脑裂后,只重配节点、不校验 journal 状态,等于把同一颗雷又埋了一遍。


















