$merge卡住oplog复制流,因其将批量操作拆解为大量细粒度写入,远超从节点消费能力;根本原因是从节点i/o配置不足,需关闭journal、调大cachesizegb,并监控oplog缓冲队列与磁盘延迟。

为什么$merge会卡住oplog复制流
$merge不是原子写操作,它在主节点上会拆解为大量细粒度的insert、update、delete操作,并逐条写入oplog。当批量执行时(比如处理百万级文档),这些操作会密集塞满oplog缓冲区,导致从节点拉取和应用速度跟不上——本质是oplog“生产”远快于“消费”,而非网络或磁盘本身故障。
从节点卡在RECOVERING状态的直接诱因
大批量$merge常伴随大文档更新或跨集合字段映射,容易触发WiredTiger引擎的page split或journal刷盘阻塞。此时从节点在apply阶段会出现长时间运行的applyOps操作,db.currentOp({secs_running: {$gt: 5}})能查到这类卡点。若持续超30秒,节点会自动降级为RECOVERING,并反复尝试重连主节点同步起点。
- 检查
rs.status().members[n].stateStr是否在RECOVERING与SECONDARY间抖动 - 查日志是否有
Failed to fetch missing oplog entries或Cannot read from oplog -
db.serverStatus().metrics.repl.buffer.count若持续 >2000,说明oplog队列已严重积压
别碰oplogSize,先关journal再调cache
很多人第一反应是调大oplog,但db.adminCommand({replSetResizeOplog: 1, size: 20480})只治标——真正让$merge复制不中断的是降低从节点I/O压力:
- 从节点务必设
storage.journal.enabled: false:journal对复制场景是冗余开销,关掉后apply吞吐可提升3–5倍 -
wiredTiger.cacheSizeGB至少设为热数据集的1.5倍:否则$merge过程中频繁换页,apply线程会卡在内存等待 - 主节点避免在
$merge期间执行compact或重建索引:这两类操作会阻塞oplog写入,加剧下游断流
用readConcern: "available"绕过复制阻塞
如果业务能容忍短暂不一致(比如报表类读取),可在$merge期间对读请求显式指定readConcern: "available"。它跳过等待oplog majority确认,避免读操作因复制延迟被hang住,间接缓解主节点压力。
但注意:readConcern: "available"不能用于事务内,且不会改变$merge本身的oplog生成行为——它只是让读不拖慢写。
真正卡住复制的,从来不是$merge语法本身,而是它暴露了从节点I/O配置和oplog消费能力的短板。调参前先看iostat -x 1里从节点的%util和await,超过85%或>50ms就是铁证。











