90%以上长期recovering源于oplog陈旧:主节点已覆盖从节点所需起始ts,验证需比对db.getreplicationinfo().timediffhours与日志中缺失ts的时间差,若后者更大则确认陈旧,删数据目录重做initial sync是唯一可靠解法。

节点卡在RECOVERING,先看oplog是否被覆盖
直接结论:90%以上的长期RECOVERING都源于oplog陈旧——主节点已把从节点需要的起始ts条目覆盖掉了。不是网络慢、磁盘满或配置错,而是同步起点根本不存在了。
验证方法很简单,连上主节点执行:
db.getReplicationInfo()
重点关注timeDiffHours字段,它代表当前oplog能覆盖的时间窗口(单位:小时)。再查从节点日志里报错的那条need oplog entry at timestamp XXX,把那个时间戳换算成小时差。如果后者大于前者,就确认陈旧。
更直观点,手动查主节点最新oplog:
db.oplog.rs.find().sort({$natural: -1}).limit(1)
对比日志中缺失的ts值。只要那个ts不在主节点oplog里,删数据目录重拉是唯一可靠解法。
注意:storage.oplogMinRetentionHours只影响4.4+版本的新oplog保留策略,对已卡住的节点无效;改oplogSizeMB并重启只能延长未来窗口,救不了当前状态。
initial sync中途卡死,别只盯日志里的“progress”
从节点启动后长时间停在RECOVERING,且日志反复出现InitialSync和类似"collection": "admin.system.version"的固定输出,基本就是全量同步卡住了。
常见卡点不是代码逻辑问题,而是环境瓶颈:
- 目标节点用SAS机械盘跑WiredTiger,压缩写入吞吐跟不上源库流速
- 源节点某个集合存在大量孤儿文档(orphaned documents),initial sync会逐个校验,单集合卡几小时不报错
- 防火墙只放行了从节点连主节点的27017,但MongoDB initial sync要求主节点能反向连回从节点(尤其在跨VPC/安全组场景)
-
local数据库所在磁盘空间不足——initial sync会在local.oplog.rs临时缓存大量oplog,空间不够就静默卡住
排查时别只刷新rs.status(),要实时看mongod进程的磁盘IO和内存占用。卡在某个collection不动超过30分钟,基本可判定是硬件或数据质量问题。
oplog大小设置不当,会同时拖慢initial sync和增量同步
很多人以为oplog只是为增量同步服务,其实initial sync也强依赖它:同步过程中所有变更都会先写进目标节点的oplog缓存,等克隆完再回放。oplog太小 → 缓存溢出 → 同步中断 → 状态卡在RECOVERING。
生产环境建议按这两条硬指标设:
- oplog容量 ≥ 预估initial sync耗时 × 平均每秒oplog写入量(可用
db.serverStatus().metrics.repl.buffer估算) - oplog窗口 ≥ 业务最长维护/迁移/故障恢复时间(比如计划停机4小时,oplog至少保留6小时)
旧版本(如3.2.x)无法在线调大oplog,必须停机删数据目录重建;3.6+支持replSetResizeOplog命令,但仅限WiredTiger引擎且不能缩容。
别信“5%磁盘空间”默认值——150GB数据配50GB oplog,在高更新业务下可能只撑2小时。
时间不同步会导致RECOVERING状态假性卡死
从节点系统时间比主节点落后超过30秒,WiredTiger引擎下可能触发oplog timestamp validation failed,日志里看不到明确报错,但状态一直停在RECOVERING。
这不是bug,是设计行为:oplog条目带ts时间戳,用于保证因果序。时间偏差大会让节点拒绝应用“未来”的oplog,也不敢发起initial sync(怕拿到错误快照)。
检查方式:
ntpq -p
确保所有副本集节点NTP同步正常,offset绝对值控制在±500ms内。若用容器部署,注意宿主机与容器时钟隔离问题——有些K8s环境需显式挂载/etc/localtime并启用hostTime。
这个点最容易被忽略:所有日志看起来都正常,rs.status()显示连接成功,就是状态切不过去。











