MongoDB事务提交需多数节点写入成功,而非仅主节点落盘;默认writeConcern为{w:"majority"},要求oplog被大多数可投票节点确认后commitTransaction才返回成功。

事务提交前必须等 Majority 节点写入成功
MongoDB 事务的持久性不取决于主节点(Primary)单独落盘,而是由 writeConcern 决定。默认开启事务时使用 {w: "majority"},意味着:事务日志(oplog)必须被集群中大多数可投票节点(包括 Primary + 多数 Secondary)成功写入并确认,commitTransaction 才会返回成功。
例如 3 节点副本集(1 Primary + 2 Secondary),Majority = 2;5 节点则 Majority = 3。少于该数量节点在线,事务无法提交——不是延迟,而是直接报错 WriteConcernFailed。
- Secondary 节点必须配置
votes: 1且priority > 0才参与 Majority 计算 - 隐藏节点(
hidden: true)、延迟节点(slaveDelay > 0)默认不计入 Majority,除非显式设置votes: 1 - 仲裁节点(Arbiter)有
votes: 1但不存数据,它能凑数达成 Majority,却不能提供数据冗余
多级副本集里“多数”可能跨数据中心失效
当副本集跨地域部署(如北京 2 节点 + 广州 2 节点 + 上海 1 节点),物理网络延迟和分区风险会让 Majority 机制暴露弱点:一次机房断网可能导致本地多数不可达,事务卡住或回滚。
此时不能只看节点数量,要看实际可通信的、满足 members[n].stateStr === "SECONDARY" 且能响应心跳的节点数。MongoDB 不会自动剔除网络隔离但未降级的节点——它仍会计票,直到心跳超时(默认 10 秒)并触发 REMOVED 状态。
- 用
rs.status().members实时检查各节点health和stateStr,别只信rs.conf() - 避免在跨中心场景下依赖纯数量 Majority;应结合
tag使用带标签的 writeConcern(如{w: 2, wtimeout: 5000, wtag: "dc:bj"}),但注意事务不支持自定义 tag writeConcern,只能靠应用层分片路由控制 - 如果广州机房整体失联,北京+上海共 3 节点仍够 Majority,但广州 Secondary 的 oplog 同步会停滞,恢复后需全量同步(initial sync)而非增量追赶
事务日志(oplog)同步与数据可见性的时序差
事务提交成功 ≠ 所有 Secondary 立即可读到最新数据。oplog 条目写入 Secondary 是异步拉取+重放的,中间存在窗口期。即使所有节点都完成了 Majority 写入,Secondary 上的 readConcern: "majority" 查询仍可能因重放延迟返回旧值。
这是因为 MongoDB 的 readConcern: "majority" 依赖节点本地的 lastAppliedOpTime 和 lastStableOpTime 判断是否已稳定应用——而重放是单线程串行的,大事务或慢磁盘会导致 lag。
- 监控
db.serverStatus().metrics.repl.buffer.count和.appliedOpTime差值,超过 1s 建议告警 - 应用若需强一致读,应在同一会话中使用
startTransaction+readConcern: "snapshot",但 snapshot 仅对事务内读有效,不对外部 Secondary 生效 - 不要在事务提交后立刻发一个新连接去 Secondary 查结果——它大概率还没追上;要么查 Primary,要么加 sleep(不推荐),要么用
rs.printSlaveReplicationInfo()等待
隐式事务与显式事务在 Majority 确认上的行为差异
从 4.2 开始,单文档写操作(如 updateOne)在副本集上默认走隐式事务,也受 w: "majority" 约束;但它的生命周期短、无会话绑定,失败时自动重试(driver 默认开启),掩盖了 Majority 不满足的问题。
而显式事务(session.startTransaction())把多个操作绑在一起,一旦任意一步触发 Majority 超时或节点离线,整个事务 abort,且 driver 不自动重试——你得自己捕获 TransientTransactionError 并重试整个逻辑块。
- 隐式事务的 writeConcern 可被单条命令覆盖,如
coll.updateOne(..., {writeConcern: {w: 1}});但显式事务中所有操作强制继承事务启动时的 writeConcern,无法 per-operation 调整 - 显式事务要求 session 必须 pinned 到同一个 mongos(分片集群)或 primary(副本集),切换节点会导致
NoSuchTransaction错误 - 长时间运行的事务(> 60s)可能被 server 中断,抛
TransactionLifetimeLimitExceeded,此时 Majority 确认根本没机会完成


















