replication lag 应看 optimeDate 差值而非 lastHeartbeatRecv;optimeDate 停滞或为 1970 年表明同步异常;需结合 currentOp、replSetGetStatus 和 95 分位 replApply 耗时综合诊断。

replication lag 要看 optimeDate,不是 lastHeartbeatRecv
很多人用 rs.status() 看复制延迟,第一反应是比对 lastHeartbeatRecv 和当前时间,这是错的。心跳时间只反映网络连通性,和实际数据同步进度无关。真正决定 lag 的是主节点和从节点各自的 optimeDate(即最后应用的 oplog 时间戳)。
实操建议:
- 在主节点执行
rs.status(),找到每个成员的optimeDate字段 - 用主节点的
optimeDate减去从节点的optimeDate,差值就是秒级 lag(注意时区一致) - 如果从节点
optimeDate是ISODate("1970-01-01T00:00:00Z"),说明它根本没开始同步或已严重落后 - 别依赖
pingMs或health字段判断同步质量——健康 ≠ 同步及时
复制缓冲区积压得查 currentOp + replSetGetStatus 组合指标
MongoDB 没有直接叫“复制缓冲区”的监控项,所谓积压,本质是 secondary 读取 oplog 的速度跟不上 primary 写入速度,导致内存中待处理 oplog 条目堆积。这需要交叉验证两个来源:
实操建议:
- 运行
db.currentOp({ "secs_running": { "$gt": 30 }, "secs_running": { "$exists": true } }),重点看secs_running高且desc含ReplExec的操作——这是复制线程卡住的信号 - 在
rs.status()输出里检查members[n].stateStr是否为SECONDARY,同时members[n].uptime是否远小于其他节点(可能刚重启,正在追 oplog) - 若
members[n].optimeDate停滞不动超过 1 分钟,且members[n].lastHeartbeat正常更新,基本可断定复制线程阻塞,而非网络问题 - 注意:4.2+ 版本中,
replSetGetStatus返回的member[n].lastAppliedWallTime比optimeDate更准,尤其在开启 causal consistency 时
db.printSlaveReplicationInfo() 只适用于简单场景,线上必须绕开
这个 shell 辅助函数看起来方便,但它只取 local.oplog.rs 的第一条和最后一条时间戳做估算,不考虑 oplog 截断、滚动、secondary 延迟启动等真实情况,在生产环境误差常达数分钟甚至更久。
实操建议:
- 开发/测试环境快速摸底可用,但告警、SLO、容量评估等场景严禁依赖它
- 替代方案:用
db.getSiblingDB("local").oplog.rs.aggregate([ { $sort: { $natural: -1 } }, { $limit: 1 } ])手动查最新 oplog 时间,再和 secondary 的optimeDate对比 - 如果副本集启用了
oplogSizeMB小于 1GB(比如默认 5% 磁盘空间但磁盘很大),oplog 循环过快会导致printSlaveReplicationInfo显示“lag=0”,实际 secondary 已经丢数据 - 云数据库(如 Atlas、MongoDB Cloud)通常屏蔽
local库访问,此命令直接不可用
流速率评估不能只看平均值,要盯住 replApply 的 95 分位耗时
复制流速率不是“每秒多少 ops”,而是“每条 oplog 平均多久被 secondary 应用”。瓶颈往往藏在慢操作里:大文档更新、索引重建、WiredTiger cache 不足都会让个别 oplog 条目卡住几秒甚至几十秒,拖垮整体流速。
实操建议:
- 启用 MongoDB 4.4+ 的
diagnosticData日志级别(logComponentVerbosity: { replication: { verbosity: 2 } }),抓取replApply耗时日志行 - 用
mongostat --host <primary> --eval 'db.serverStatus().metrics.repl.apply' -n 1</primary>实时观察num(已应用数)和totalMillis(总耗时)变化率 - 计算 95 分位耗时:若
totalMillis / num > 500(毫秒),说明存在显著长尾;此时应检查 secondary 的db.serverStatus().metrics.document中deleted和updated是否突增(可能正批量回填) - 避免在 secondary 上执行
db.collection.find().explain("executionStats")—— 这会触发全表扫描,进一步抢占复制线程资源
真正难监控的不是 lag 数值本身,而是 lag 的波动模式:突然跳变、阶梯式上升、周期性卡顿……这些背后往往是 oplog 写放大、WiredTiger cache pressure 或跨数据中心带宽抖动。数值只是症状,得结合 netstat -s、iostat -x 1 和 MongoDB 日志里的 repl 模块输出一起看。

















