最准、最轻量的方式是读取 serverStatus 中的 opcountersRepl 字段,它仅统计主节点写入 oplog.rs 的 insert/update/delete 操作累计次数,需两次采集做差除以时间间隔得实时速率。

查 oplog 实时写入速率,直接看 serverStatus 里的 opcountersRepl
MongoDB 副本集的 Oplog 写入量不等于主节点所有写入量,而是专指被记录进 local.oplog.rs 的操作数(即真正参与复制的操作)。最准、最轻量的方式就是读 serverStatus 中的 opcountersRepl 字段——它只统计写入 Oplog 的 insert、update、delete 操作,不含命令、查询或内部心跳。
实操建议:
- 在主节点上执行
db.runCommand({serverStatus: 1}),然后定位到opcountersRepl对象 - 该对象下三个字段:
insert、update、delete,单位是「自启动以来的累计次数」,不是实时速率 - 要算每秒写入量,需间隔 N 秒两次采集,做差值再除以 N;比如间隔 5 秒,
insert从 12000 变成 12500,则平均100 op/s - 注意:4.4+ 版本中,
opcountersRepl不再包含command类型(如applyOps),避免误把批量回放当实时写入
collStats 看 local.oplog.rs 大小变化不靠谱
有人想通过监控 local.oplog.rs 集合的 size 或 count 变化来估算写入速率,这容易出错。Oplog 是固定大小的 Capped Collection,写入时旧文档会被覆盖,count 值会震荡,size 因 BSON 开销和压缩不可线性换算成操作数。
常见错误现象:
- 刚重启后
count很小,但写入压力其实很高 → 误判为低负载 - 大量小文档更新导致
size增长慢,但opcountersRepl.update涨得飞快 → 低估真实复制压力 - 使用
db.local.getCollection('oplog.rs').stats()频繁调用,可能触发 collection scan,影响主节点性能
聚合管道 + $dateDiff 算最近 N 秒 Oplog 条数?太重,别这么干
想精确知道「过去 10 秒内写了多少条 Oplog」,有人会查 local.oplog.rs 的 ts 字段,用聚合加 $dateDiff 统计。这在语法上可行,但实际非常危险:
- Oplog 默认不建索引(
ts字段虽有隐式索引,但聚合扫描仍可能扫全量,尤其当 Oplog 较大时) - 主节点高写入场景下,这类查询容易阻塞写入,甚至触发
maxTimeMS超时或InterruptedDueToReplStateChange -
$dateDiff是 5.0+ 才支持,老版本直接报错unrecognized pipeline stage name: '$dateDiff' - 即使成功,结果也只是近似值——因为 Oplog 写入和查询存在毫秒级时序差,且
ts是时间戳,非严格单调(受时钟漂移影响)
监控脚本里怎么安全取值?用 mongosh + JSON.parse() 解析 serverStatus
写监控脚本时,别用 mongo shell(已弃用),统一用 mongosh;也别依赖 shell 输出格式(随时可能变),应解析 JSON 结构。
示例(Shell 脚本中):
mongosh --quiet --eval 'db.runCommand({serverStatus: 1}).opcountersRepl' mongodb://localhost:27017
输出是纯 JSON,可直接用 jq 提取:
-
jq '.insert + .update + .delete'得总 Oplog 操作累计数 - 两次调用之间用
sleep 1控制间隔,避免高频请求打满连接数 - 务必加
--quiet,否则输出含 banner 和提示符,jq会解析失败 - 如果副本集启用了访问控制,记得传
--username、--password和--authenticationDatabase admin
真正的难点不在取数,而在于理解 opcountersRepl 是「仅主节点写入 Oplog 的计数」——Secondary 上查不到这个值,也不能拿它反推应用层 QPS。漏掉这点,指标就完全跑偏了。










