w:1 是丢数据的直接原因,因仅主节点落盘即返回成功,主节点宕机或切换时未同步的数据将永久丢失。

WriteConcern 设置为 w:1 是丢数据的直接原因
副本集主节点切换时丢数据,绝大多数情况不是网络或硬件问题,而是写入时没要求多数节点确认。当 writeConcern 设为 {w: 1}(默认值),MongoDB 只等主节点落盘就返回成功;一旦主节点在同步到从节点前宕机、被踢出副本集或触发选举,那些只写在它内存/日志里、还没复制出去的数据就永久丢失了。
常见错误现象:mongosh 执行插入后立刻看到结果,但主节点切走再查就没了;或者用 rs.status() 发现原主节点的 optime 明显落后于其他成员,说明它积压了未同步的操作。
- 所有驱动默认都用
w: 1,不显式设置就等于“不保安全” -
w: "majority"才表示写入到大多数节点(含主)的 oplog 后才返回,这是防丢数据的底线 - 注意:即使设了
w: "majority",如果当前存活节点数不足多数(比如 3 节点集群挂掉 2 个),写操作会阻塞或报错NotMasterOrSecondary,而不是降级执行
journal 和 writeConcern 的关系常被误解
开启 journal(默认开启)只能保证单节点崩溃重启后不丢已提交的写入,但它不解决副本集维度的数据可见性问题。一个写操作即使刷了 journal,只要没复制到其他节点,在主节点被强制下线时,新主节点根本不知道这条数据存在。
使用场景:你依赖 journal 来防止机器断电丢数据,但副本集高可用必须靠 writeConcern + readConcern 组合保障。
-
journal: true是本地持久化保障,和副本同步无关 -
w: "majority"+j: true才真正实现“多数节点持久化”,即写入被多数节点刷盘后才返回 - 若只设
j: true但w: 1,仍可能丢数据——因为从节点根本没收到这条操作
选举窗口期暴露弱 WriteConcern 的风险
主节点不可用到新主选出之间(通常几秒),客户端仍在向旧主发请求。如果此时旧主还接受写入(比如心跳超时未及时降级),而你的 writeConcern 又是 w: 1,这些写入就成了“幽灵写入”:它们在旧主上成功,但不会出现在新主的 oplog 中,也不会被任何从节点复制。
性能影响:提高 writeConcern 等级会增加写延迟,尤其跨机房部署时。但比起丢数据,这点延迟更可控。
- 避免在选举频繁的集群中使用
w: 1,尤其是金融、订单类业务 - 可通过
rs.conf()检查settings.electionTimeoutMillis(默认 10s),超时越短选举越快,但也越容易误触发 - 监控
metrics.repl.buffer.count和oplog.window,判断从节点同步是否长期滞后
readConcern 和 writeConcern 必须配对使用
只设强 writeConcern 不够,读的时候还得配 readConcern: "majority",否则可能读到被回滚的数据。例如:旧主在选举前写了 A,新主选出来后发现 A 不在自己的 oplog 里,就会把 A 回滚;但如果你用 readConcern: "local",可能刚巧读到这段已被回滚的 A。
容易踩的坑:很多应用写用 w: "majority",读却用默认 "local",导致“写进去又读不到”或“读到后来消失的数据”。
-
readConcern: "majority"保证只读到已提交到多数节点的数据 - 注意驱动版本兼容性:Node.js 驱动 4.0+、Python PyMongo 4.0+ 才默认支持
readConcern多数读 - 事务内自动启用
readConcern: "snapshot",但普通命令仍需显式指定
w: "majority" 和 readConcern: "majority" 是副本集数据一致性的最小安全组合。很多人卡在“测试环境没出事所以不改”,但真实故障往往发生在流量高峰叠加节点异常的瞬间——那时没设对的 WriteConcern 就成了最后一根稻草。











