MongoDB副本集Oplog空间不足怎样扩容?

作者:袖梨 2026-07-07
Oplog 真正不够用的明确信号是 Secondary 执行 db.oplog.rs.findOne({ts: {$lt: ObjectId("...")}}) 返回 null,或日志出现 OplogStartMissing、lag 持续增长且 timeDiffHours 小于实际 lag;MongoDB 4.4+ 可用 replSetResizeOplog 在线扩容(需 WiredTiger 引擎、FCV=4.4、size≥990MB 并用 Double() 包裹),否则须滚动重建节点。

确认 Oplog 真的不够用了,别只看 timeDiffHours

db.getReplicationInfo() 返回的 timeDiffHours 是主节点估算值,不能直接当“还剩多少小时”用。真正失效的信号在从节点上:
在 Secondary 执行 db.oplog.rs.findOne({ts: {$lt: ObjectId("...")}}),其中 ObjectId 来自主节点 rs.status().members[0].optime.ts。返回 null 就说明该时间点前的日志已被覆盖。
其他明确信号包括:
• Secondary 日志反复出现 OplogStartMissingNeed to reclone collection due to oplog gap
rs.printSlaveReplicationInfo() 显示 lag 持续增长,且 timeDiffHours 已小于最大 lag 值(比如 lag 到了 3600 秒,但 timeDiffHours 只剩 0.8)

MongoDB 4.4+:用 replSetResizeOplog 在线扩容,但必须满足三条件

这个命令不是“改配置”,而是重设 capped 集合的 maxSize,全程不重启、不影响读写,但有硬性前提:
• 所有节点已升级到 MongoDB 4.4+,且 featureCompatibilityVersion 设为 "4.4"(执行 db.adminCommand({setFeatureCompatibilityVersion: "4.4"})
• 存储引擎必须是 WiredTiger(MMAPv1 不支持)
size 参数必须是 Double() 包裹的数值,单位 MB,且 ≥ 990
在 Primary 上执行示例:
db.adminCommand({replSetResizeOplog: 1, size: Double(10240)})(扩到 10GB)
注意:
• 不能对正在 initial sync 或状态异常(如 STARTUP2 卡住)的节点执行
• 扩容后立刻验证:db.getReplicationInfo().maxSizeMB 应更新,再回 Secondary 复测 findOne 是否能定位旧 ts

4.2 及更早版本:没有在线选项,滚动重建是唯一路径

所谓“热修改”是误导。强行删 local.oplog.rs 或用 captrunc 会破坏 capped 属性,导致节点无法启动或同步中断。
标准流程是逐个处理 Secondary:
• 停 mongod 进程
• 删除 data/db/local/oplog.rs.wt 文件(不是删集合!也不是删整个 local/ 目录)
• 启动时加参数 --oplogSize 10240(单位 MB)
• 等待自动 initial sync 完成
Primary 必须最后处理,且操作前必须 rs.stepDown(),确保至少一个 Secondary 在线提供写服务。
风险点:
• 每个节点重建期间都需完整同步数据,耗时与数据量正相关
• config server 副本集同理,但必须维持 majority 可用,否则 mongos 路由失效

容易被忽略的关键细节

最常出问题的地方不在命令本身,而在执行节奏和权限:
replSetResizeOplog 必须在每个节点单独执行,不能只改 Primary —— Secondary 同步时仍按自己本地的 maxSize 判断是否够用
• 用户必须有 clusterManagerclusterAdmin 角色,否则权限拒绝
• 扩容后磁盘空间不会自动释放;compact 只回收未用空间,但会阻塞复制,仅限维护窗口在降级后的节点上谨慎使用
• 如果 db.oplog.rs.stats().maxSize 显示只有 2GB,却设了 minRetentionHours: 72,那只是“提要求”,实际撑不过几小时——物理尺寸才是硬门槛

相关文章

精彩推荐