必须显式设为 majority 才能防丢数据:默认 w:1 仅主节点内存写入即返回,主节点宕机且未同步时数据丢失;生产环境需在客户端、数据库或集合级显式配置 w:"majority",确保多数节点持久化后才确认,事务中须单独设置且不继承默认值。

写关注(write concern)必须显式设为 majority 才能防丢数据
默认 w:1 只等主节点写入内存就返回,一旦主节点宕机且 oplog 未同步到从节点,刚写的文档就丢了。生产环境必须在客户端、数据库或集合级显式设置 MONGOC_WRITE_CONCERN_W_MAJORITY(驱动中对应 w: "majority"),确保写操作被大多数副本集成员持久化后才确认成功。
常见错误是只改了连接字符串却没调用 mongoc_client_set_write_concern(),或者误以为 w:2 就够——实际应依赖 "majority" 动态计算(比如 5 节点集群要求 3 个确认,而非硬编码为 2)。
- 事务内必须单独用
mongoc_transaction_opts_set_write_concern()设置,它不继承客户端默认值 - WiredTiger 引擎下,
w: "majority"意味着写入 journal 并刷盘,不是仅写入内存 - 如果副本集只有 2 个投票节点,
"majority"实际等价于w:2,但此时容错能力已降为 0(挂一个就无法写入),应补仲裁节点或扩容
读关注(read concern)配错会导致读到“幻影数据”
用 readConcern: "local"(默认)时,可能从 secondary 读到尚未被多数节点确认的写入;而 readConcern: "majority" 才能保证只读到已提交、不会回滚的数据。但要注意:它不能跨事务读取未提交内容,也不能解决“写后读”场景下的延迟问题。
典型踩坑:在 primary 上写完立刻用 secondary + "local" 去查,结果查不到——这不是 bug,是设计使然。若业务强依赖“写后立即可读”,必须强制读 primary(readPreference: "primary"),或搭配 readConcern: "majority" + writeConcern: "majority" 组合使用。
-
readConcern: "linearizable"可实现线性一致性读,但性能开销大,仅适用于极少数强一致场景(如金融对账) - 4.4+ 版本起,
readConcern: "majority"要求 oplog 必须开启且大小足够,否则会降级为"local"并静默忽略 - change stream 默认基于
"majority",若下游服务依赖 change stream 做实时同步,务必确认上游写操作用了匹配的 write concern
副本集状态异常时 CRUD 会静默失败或降级
当某个 secondary 卡在 RECOVERING 或 STARTUP2 状态,或 rs.status().members[n].health 为 0 时,客户端发往该节点的读请求可能超时、重试甚至路由到其他节点——但这个过程对应用层不可见。更危险的是:若配置了 readPreference: "secondaryPreferred",而所有 secondary 都不可用,请求会自动 fallback 到 primary,导致主库压力突增。
关键检查点不是“有没有 secondary”,而是 optimeDate 差值是否稳定在秒级内。用 rs.printSlaveReplicationInfo() 查看各节点延迟,超过 30 秒就要预警;若日志出现 could not find base oplog entry,说明 oplog 被覆盖,该节点已无法自动追平,必须人工重置同步。
- 不要依赖
db.isMaster()的secondary字段判断可用性,它只反映角色,不反映实时同步状态 - 监控
lastHeartbeatRecv时间戳,比stateStr更早暴露网络分区问题 - oplog 大小建议按日均写入量 × 24 小时估算,用
db.adminCommand({replSetResizeOplog: 1, size: 10240})调整需在 PRIMARY 上执行,且仅对 WiredTiger 有效
事务内 CRUD 不等于绝对强一致
MongoDB 事务确实提供 ACID 保障,但前提是整个事务生命周期内所有参与节点都保持在线且网络通畅。一旦发生 primary 故障切换,正在进行的事务会被中止,客户端收到 InterruptedDueToReplStateChange 错误——此时你得自己处理重试逻辑,驱动不会自动续传。
另一个常被忽略的点:事务内读操作默认使用 readConcern: "snapshot",但它只隔离事务开始时刻的数据快照,不阻塞其他写入。如果事务 A 修改 doc1 后,事务 B 同时修改 doc2 并提交,事务 A 提交时仍可能因写冲突失败(WriteConflict),这属于正常行为,不是数据不一致。
- 事务最大时长默认 60 秒,超时自动 abort,可通过
maxTimeMS参数调整,但过长会增加锁持有时间 - 多文档事务不能跨分片集群,只适用于单一分片或副本集内部
- 即使
w: "majority"+readConcern: "majority",也无法规避网络分区期间的脑裂风险——MongoDB 依赖多数派投票防脑裂,所以副本集节点数必须为奇数或配仲裁节点
真正难的不是配参数,是理解每个参数生效的前提条件:oplog 是否完整、节点心跳是否正常、选举是否完成、驱动版本是否支持对应特性。任何一环断裂,CRUD 行为就会悄悄偏离预期。











