oplog.rs增长过快需先确认是否真实异常:检查local.oplog.rs.stats()大小与serverStatus写入量匹配性,若>5GB且每小时>500MB而业务无变更,则排查updateMany/bulkWrite、低效查询、事务重复更新及secondary同步延迟。

查 oplog.rs 大小和增长速率
Oplog 本质是 local.oplog.rs 这个 capped collection,它不自动清理,只靠 TTL 或空间满时覆盖。先确认它是不是真在“过快”增长——别被监控曲线吓到,得看绝对值和写入节奏是否匹配业务。
- 用
db.getSiblingDB("local").oplog.rs.stats()查当前大小、文档数、平均对象大小 - 对比
db.serverStatus().metrics.operation.write.ops和db.serverStatus().opcounters中的update/command数量,看写入频次是否突增 - 如果 oplog 占用 > 5GB 且每小时增长 > 500MB,而业务没上线新批量任务,就值得深挖
定位大批量 updateMany 或 bulkWrite 操作
MongoDB 的 oplog 条目按「每个修改操作一条」记录,不是按事务或请求计。一次 updateMany({status: "pending"}, {$set: {status: "done"}}) 可能生成上万条 oplog 记录——尤其当匹配文档多、又没加 multi: false(虽然默认就是 true)时。
- 开启慢日志:在配置中设
operationProfiling.mode: "all"+operationProfiling.slowOpThresholdMs: 100,再查db.system.profile.find({op: "update", millis: {$gt: 100}}).sort({ts: -1}) - 重点关注
nMatched字段远大于nModified的更新——说明大量文档被扫描但未改,可能是查询条件没走索引,拖慢执行并拉长 oplog 写入窗口 - 避免在应用层循环调用
updateOne;改用bulkWrite并设ordered: false,减少网络往返,但注意这不会减少 oplog 条目数
事务里反复修改同一文档会放大 oplog 体积
一个事务内对同一个文档多次 $set,每改一次就记一条 oplog(即使最终只存最后一次值)。MongoDB 不合并事务内的重复更新,oplog 必须保留下游复制的精确顺序。
- 检查应用代码里有没有类似「查 → 改字段A → 改字段B → 改字段C → 提交」的模式;应合并为单次
$set: {a: x, b: y, c: z} - 事务中避免
save()或findOneAndUpdate套路,它们容易隐式触发多次写入 - 使用
db.adminCommand({currentOp: {allUsers: true, $or: [{secs_running: {$gt: 5}}, {active: true}]}})找长事务,重点看secs_running和numYields
副本集同步延迟加剧 oplog 积压的假象
Secondary 同步慢,导致主节点不敢覆盖旧 oplog(怕从节点还没拉取),看起来像 oplog “涨太快”,其实是卡住了。这时候删 oplog 或调大 size 都治标不治本。
- 运行
rs.printSecondaryReplicationInfo(),看syncingTo和optimeDate差距;差 > 60 秒就要警惕 - 检查 secondary 的磁盘 I/O:
iostat -x 1看%util是否持续 > 90%,await是否 > 50ms - 确认
replSetGetStatus中各节点的lastHeartbeatMessage是否有 “not enough space” 或 “too many open files” 类错误
真正麻烦的是那种混合场景:批量更新 + 低效查询 + 事务拆分 + secondary I/O 瓶颈——这时候光看 oplog 大小没用,得顺着写入链路一节节掐断,否则调完参数第二天又爆。

















