MongoDB 的 oplog 是什么?复制延迟怎么排查?
简化版
oplog 是复制集里记录写操作历史的特殊 capped collection,Secondary 通过拉取并重放 Primary 的 oplog 来同步数据。复制延迟通常要看写入压力、网络、磁盘、索引、长事务、Secondary 负载和 oplog 窗口是否足够。
详细版
MongoDB 复制不是简单拷贝数据文件,而是 Primary 记录逻辑写操作到 oplog,Secondary 按顺序应用这些操作。oplog 是固定大小的循环集合,写入太快而 Secondary 追不上时,旧 oplog 可能被覆盖,节点就需要重新同步。
排查复制延迟时可以看 rs.printSecondaryReplicationInfo()、复制状态、网络 RTT、磁盘 I/O、慢操作、索引构建、长事务和读流量是否压在 Secondary 上。回答时要强调:oplog 是复制基础,复制延迟不是单一原因,要从写入速度、应用速度和 oplog 保留窗口一起分析。
完整版教学
一、oplog 是复制集同步的操作日志
MongoDB 复制集里,Primary 负责接收写入,并把写操作记录到 oplog。Secondary 持续读取 Primary 或其他同步源的 oplog,然后在本地重放这些操作。
它记录的是逻辑操作,而不是完整数据文件拷贝。这样复制可以持续增量进行,也便于 Secondary 从某个时间点继续追。
client write
|
v
Primary data change
|
v
local.oplog.rs
|
v
Secondary pull and apply
记忆钩子:复制集的数据同步靠 oplog 接力,Primary 写一笔,Secondary 追一笔。
二、oplog 为什么是 capped collection
oplog 是一个特殊的 capped collection,也就是固定大小、按插入顺序循环覆盖的集合。它不会无限增长。
这个设计有好处:空间可控,顺序写入和顺序读取效率高。但它也带来一个关键指标:oplog window,也就是从最老一条 oplog 到最新一条 oplog 覆盖的时间范围。
| 写入速度 | oplog 大小 | oplog window | 风险 |
|---|---|---|---|
| 低 | 大 | 可能数天 | 节点短暂停机可追上 |
| 高 | 小 | 可能几小时 | Secondary 容易追丢 |
| 突增 | 不变 | 快速缩短 | 批量导入时要特别关注 |
如果 Secondary 落后时间超过 oplog window,旧操作已经被覆盖,它就不能靠增量复制追上,通常需要重新同步。
三、复制延迟的本质是生产速度大于消费速度
复制延迟可以理解为 Primary 生成 oplog 的速度,超过了 Secondary 拉取和应用 oplog 的速度。
常见原因包括:
- Primary 写入太猛,比如批量导入、热点更新。
- Secondary 磁盘慢,应用 oplog 跟不上。
- 网络抖动,拉取 oplog 不稳定。
- Secondary 同时承担读请求、备份或分析任务。
- 索引过多,每次写入在 Secondary 上也要维护索引。
- 长事务或大事务让提交和复制压力集中。
面试里不要只说“加机器”,要能讲清楚延迟来自哪里。
四、复制延迟会影响读一致性和故障恢复
如果业务把读请求路由到 Secondary,复制延迟会导致读到旧数据。比如用户刚改昵称,下一次请求读 Secondary,可能仍然看到旧昵称。
T0 Primary: name = "Alice"
T1 update name = "Alicia"
T2 Secondary still lag 5s
T3 read from Secondary -> "Alice"
延迟还会影响故障恢复。如果 Primary 宕机,某个落后的 Secondary 被选为新 Primary,就可能丢失尚未复制到多数节点的写入。实际风险与 write concern、选举、节点状态有关。
所以复制延迟不是监控好看不好看的问题,而是直接关系到读新鲜度和高可用质量。
五、排查复制延迟要看 3 类指标
可以把排查分成 3 层。
| 层次 | 关注指标 | 典型动作 |
|---|---|---|
| 生产端 | 写 QPS、oplog 增长速度、慢写 | 降低批量写峰值,减少无效索引 |
| 传输端 | 网络 RTT、丢包、同步源 | 检查跨机房链路,调整同步源 |
| 消费端 | Secondary I/O、CPU、锁、慢操作 | 减少读压,升级磁盘,拆分任务 |
常用命令包括:
rs.status()
rs.printSecondaryReplicationInfo()
db.getSiblingDB("local").oplog.rs.find().sort({ $natural: -1 }).limit(1)
命令只是入口,关键是把结果和业务写入模式联系起来。
六、oplog 窗口不足怎么处理
如果 oplog window 太短,可以考虑增大 oplog 大小。但只增大 oplog 不是根治,它只是让 Secondary 有更长时间追赶。
还需要处理根因:
写入突增 -> 削峰批处理
索引过多 -> 删除无用索引
Secondary 负载高 -> 读写隔离或独立分析库
磁盘瓶颈 -> 提升 IOPS
跨地域复制 -> 接受延迟或调整架构
对生产环境,尤其是大批量导入、重建索引、迁移数据前,要提前评估 oplog window,避免操作进行一半发现从库追丢。
七、常见误区与追问
- 误区:oplog 是普通业务日志。 oplog 是复制机制使用的操作历史,位于
local库,不是给业务审计随便消费的日志。 - 误区:Secondary 落后一点无所谓。 如果读走 Secondary,会影响读新鲜度;如果窗口不够,还可能导致重新同步。
- 误区:复制延迟只和网络有关。 写入压力、磁盘 I/O、索引维护、长事务和 Secondary 读负载都可能导致延迟。
- 追问:oplog window 是什么? 是 oplog 当前能覆盖的时间跨度,决定落后节点还能靠增量复制追多久。
- 追问:为什么 oplog 是 capped collection? 固定空间、顺序写读效率高,但旧记录会被循环覆盖。
- 追问:怎么降低复制延迟? 先定位生产、传输、消费哪一层慢,再针对写峰值、网络、磁盘和从库负载处理。
八、加强记忆
MongoDB oplog 题可以记成“写入产生、从库追赶、窗口兜底”。Primary 把逻辑写入放进 oplog,Secondary 拉取并重放;oplog 是固定大小的 capped collection,所以有窗口概念;复制延迟本质是生成速度大于应用速度。排查时沿着 Primary 写入、网络传输、Secondary 应用三段看,别把问题简单归因成网络慢。