w:majority + j:true 是防丢数据的最小可行组合,需满足节点数、投票权和journal启用三前提;w:1因仅写入主节点内存oplog即返回,断电即丢数据,非安全默认值。

w:majority + j:true 是防丢数据的最小可行组合,但必须满足节点数、投票权和 journal 启用三个前提
为什么默认 w:1 会丢数据
主节点写入内存 oplog 后就返回成功,此时若主节点断电或崩溃,且尚未同步到任何从节点,该写入永久丢失。日志(journal)未刷盘、无副本确认,w:1 只保证“主节点收到了”,不保证“能活下来”。
-
w:1是驱动默认值,不是安全默认值 - 即使配置了副本集,不显式设
w:"majority",事务或单条写入仍走w:1 -
WriteConcern.ACKNOWLEDGED(即w:1)在 Spring Data MongoDB 中是 save() 的默认行为,容易误以为已持久化
事务中必须提前设置 session 级 writeConcern
不能在 session.startTransaction() 调用里传参,也不能在 insertOne() 或 updateOne() 的 options 里单独设——事务内所有操作强制继承 session 的 writeConcern。
- Node.js:必须在
session.startTransaction()前赋值session.options.writeConcern - Python PyMongo:用
session.start_transaction(write_concern=WriteConcern(w="majority", j=True)) - Java:先
session.setWriteConcern(WriteConcern.MAJORITY.withJournal(true)),再startTransaction() - 错误写法:
collection.insertOne(doc, { session, writeConcern: { w: "majority" } })—— 该字段会被忽略
“majority” 不是“所有节点”,而是“大多数投票节点”
计算方式取决于 rs.conf() 中 members[n].votes > 0 的节点个数。非投票节点(如 votes: 0 或 priority: 0 + slaveDelay)不参与 majority 计算,即使它们有数据。
- 3 节点副本集(PSS),
majority = 2;5 节点(PPSSS),majority = 3 - 如果加了一个
votes: 0的延迟从节点,它不会让 majority 变成 3(3 节点时) - 所有参与 majority 的节点必须启用
journal: true(默认开启,但磁盘满或配置被覆盖时可能失效) - 检查命令:
rs.status().members.filter(m => m.stateStr !== "PRIMARY" && m.stateStr !== "SECONDARY"),避免RECOVERING或UNKNOWN节点拉低可用投票数
超时或 WriteConcernFailed 的真实原因
不是配置错了,而是多数节点没能在 wtimeoutMS(默认 0,即无限等待)内完成 oplog 持久化。常见于磁盘 I/O 延迟高、journal 刷盘慢、或某投票节点失联。
- 不要盲目调大
wtimeoutMS,先查rs.status()和系统磁盘负载 -
j:true强制 journal 刷盘,若磁盘慢,w:"majority"就会卡住 - 脑裂场景下,原主节点降级为 secondary 后无法获得多数票,新主节点也无法凑够 majority —— 此时任何
w:"majority"写入都会失败 - 真正容易被忽略的一点:
w:"majority"只保障“已确认写入”的可恢复性;若写入还没走到 oplog 阶段(比如 BSON 解析失败、内存分配失败),它根本不会触发,也谈不上防丢











