副本集本身不自动防止数据丢失,真正防丢需writeconcern设为"majority"、足够大的oplog窗口及独立备份机制三者缺一不可。

副本集本身不自动防止数据丢失,它只提供冗余和故障转移能力;真正防止关键业务数据丢失,必须配合写关注(writeConcern)策略、oplog保留窗口控制、以及外部备份机制——三者缺一不可。
写关注(writeConcern)必须设为 "majority" 而非默认 1
默认的 writeConcern: 1 表示只要主节点写入成功就返回确认,此时若主节点在同步到从节点前崩溃,且选举出的新主节点恰好是旧数据更少的那个,就会发生“回滚丢失”。
生产环境必须显式设置:
db.collection.insertOne({x: 1}, {writeConcern: {w: "majority", wtimeout: 5000}})
这意味着:写操作必须被大多数节点(如 3 节点集需至少 2 个)成功写入并确认,才向客户端返回成功。这能杜绝多数派选举导致的数据回滚。
常见错误现象:
- 应用未指定
writeConcern,误以为“写进去了就安全了” - 设置了
w: 2但副本集只有 3 个节点,其中 1 个长期失联——此时“多数”仍是 2,但实际可用节点只剩 2 个,w: 2等价于w: "majority";但如果节点数变为 4,w: 2就不再满足多数(多数为 3),反而降低安全性 -
wtimeout过短(如 100ms),在网络抖动时频繁报WriteConcernFailed,但业务没做重试或降级处理
oplog 大小必须支撑最长可能的恢复时间窗口
oplog 是副本集内节点间复制的“日志”,它的大小决定了从节点断连后还能追上主节点的最长时间。如果 oplog 太小,从节点断连超过该窗口,再上线时只能触发全量初始同步(initial sync),期间无法提供读服务,且加重主节点压力。
判断依据不是“平均延迟”,而是“最长单次网络分区时长 + 故障响应与修复时间”。例如:
- 你所在区域曾发生过 35 分钟的跨机房网络中断 → oplog 至少保留 60 分钟数据
- 运维 SLO 要求 15 分钟内完成节点替换 → 加上缓冲,oplog 建议按 90 分钟预估
查看当前 oplog 大小:
rs.printReplicationInfo()
调整方法(需在每个节点执行,且必须停机):
mongod --replSet rs0 --oplogSize 10240 --dbpath /data/db
注意:--oplogSize 单位是 MB,且只对新初始化的节点生效;已有节点需先 rs.remove() 再重建,或使用 collMod 命令(仅限 4.4+,且有严格限制)。
备份不能只靠副本集,必须独立运行 mongodump 或文件系统快照
副本集防的是硬件故障、进程崩溃、单节点数据损坏;它防不了人为误删(db.collection.drop())、逻辑错误(批量更新条件写错)、勒索软件加密整个 dbpath ——这些操作会立刻同步到所有副本。
所以必须有离线、异构、带时间戳的备份:
- 每日全量 + 每小时增量(用
mongodump --oplog配合上次备份的 oplog 时间戳) - 备份必须存放在与 MongoDB 集群物理隔离的位置(不同 AZ、不同云厂商、甚至离线磁带)
- 定期验证恢复流程:用备份启动一个临时单节点
mongod,连上mongosh查一条关键业务记录是否可读
特别注意:在 secondary 节点执行 mongodump 时,务必加 --readPreference=secondary,否则默认连 primary,可能拖慢写入。
最容易被忽略的一点:仲裁节点(Arbiter)不参与数据持久化,也不保存 oplog,它只投票。哪怕你的副本集配置了 5 个节点,其中 2 个是 arbiter,那真正承担数据安全责任的仍是那 3 个 data-bearing 节点——它们的写关注、oplog、备份,才是关键业务数据不丢失的最终防线。











