跳到正文

MongoDB 监控指标与告警 ​

一句话:MongoDB 的监控要沿「主机 → mongod 进程 → 副本集/分片 → 业务」四层走;它的强项是文档模型和水平扩展,代价是 cache、checkpoint、oplog 这三处有上限的资源,故障几乎都从这三处开始。

适用版本:MongoDB 6.0 / 7.0 / 8.0。字段和默认值随版本变化,以官方文档为准。

为什么需要 ​

MongoDB 不会因为「连接能建立」就代表健康。写入先落在 WiredTiger cache 和 journal,再由 checkpoint 刷盘,由 oplog 复制到从节点。cache 脏页、checkpoint、oplog 窗口任何一个先坏,表现都不是进程退出,而是写入变慢、连接堆积、从节点追不上。等应用报超时,通常已经错过了最佳处置窗口。

核心机制 ​

四层观察面 ​

层看什么回答的问题
主机CPU、内存、磁盘 IOPS/延迟/空间、swap是不是磁盘或内存先到极限
进程serverStatus 的连接、opcounters、queues、cache、checkpoint、assertsmongod 内部是否在排队或刷不动
副本集/分片rs.status、oplog 窗口、lag、chunk 分布、balancer复制和路由是否还能兜住故障
业务延迟、错误率、写关注超时、连接池等待、回源用户是否已经受影响

主机层:磁盘是隐形瓶颈 ​

WiredTiger 的写路径是「写 cache → 写 journal → checkpoint 刷数据页」。journal 默认按时间批量提交(约 100ms,以官方文档为准),checkpoint 至少每 60 秒一次。磁盘延迟升高时,journal 提交和 checkpoint 都变慢,cache 里的脏页越积越多,最后应用线程被迫参与淘汰,写延迟陡增。所以磁盘不只看使用率,还要看 await、IOPS 和写放大;swap 一旦被使用,cache 的访问延迟会直接失控。

进程层:连接、队列、cache、checkpoint、asserts ​

  • 连接:serverStatus().connections.current 是当前连接数,available 是还能接多少。available 接近 0 时新连接被拒,但根因往往不是连接泄漏,而是前面的操作变慢导致连接不释放。要同时看应用侧连接池等待。
  • 操作计数:opcounters(insert/query/update/delete/getmore/command)是累计值,看斜率而不是绝对值。某类操作斜率突变,通常对应一批新查询或重试风暴。
  • 队列:queues.execution 是等待执行的操作数,globalLock.currentQueue 的 readers/writers 是等锁的读写数(字段名随版本变化,以官方文档为准)。队列持续不为 0,说明并发已超过服务能力,继续加连接只会更糟。
  • WiredTiger cache:bytes currently in the cache 对比 maximum bytes configured 看用量,tracked dirty bytes in the cache 看脏页比例。cache 用满本身正常——它本来就是装热数据的;异常的是脏页比例高、pages read into cache 暴涨、modified pages evicted 增长,这些说明正在被磁盘拖着走。WiredTiger 的 eviction_dirty_target / eviction_dirty_trigger 默认按 cache 百分比配置(默认 5 / 20,以官方文档为准):脏页超过 target 后台开始淘汰,超过 trigger 应用线程被迫参与,延迟明显上升。
  • checkpoint:看 wiredTiger.transaction 里的 transaction checkpoint most recent time (msecs),以及 cache 里的 checkpoint blocked page eviction。checkpoint 变慢会反过来阻塞淘汰,形成「脏页刷不掉 → 淘汰等 checkpoint → 写更慢」的循环。
  • asserts:asserts.regular / warning 的增长比任何性能指标都值得优先看,它可能意味着数据一致性问题,不是调参能解决的。
  • 扫描效率:docsExamined / keysExamined / nReturned 来自 explain、profiler 或慢日志。docsExamined 远大于 nReturned,说明索引没覆盖住,扫描会把冷页读进 cache,挤掉热数据;排序阶段出现 SORT_KEY_GENERATOR 或内存排序触顶,也会额外占内存和 CPU,表现为延迟升高而不是报错。
  • 版本与 FCV:db.version() 和 db.adminCommand({getParameter:1, featureCompatibilityVersion:1}) 要纳入变更记录。升级后 FCV 不一致会让节点无法加入或行为分叉,这类问题在指标上往往先表现为复制异常。

副本集与分片层 ​

  • 复制:rs.status() 看每个成员的 stateStr、health、optimeDate;rs.printReplicationInfo() 给 oplog 时间窗口;rs.printSecondaryReplicationInfo() 给 lag。lag 要对比窗口看——lag 30 秒但窗口有 24 小时,和 lag 30 秒但窗口只有 5 分钟,风险完全不同。
  • 提交点:多数派写关注等的是 lastCommittedOpTime。从节点慢会拖慢提交点,主节点上的 w:"majority" 写就会变慢甚至 wtimeout,表现为「主节点没故障,但写入变慢」。
  • 分片:sh.status() 看 chunk 分布、jumbo chunk 和 balancer 状态。chunk 迁移会同时压网络、源 shard 和目标 shard,看到迁移流量先确认是不是均衡器在工作,不要当成故障。

两条典型的雪崩链路 ​

链路一:脏页逼近阈值 → checkpoint 压力 → 写延迟升高 → 连接堆积。 写入速率超过磁盘刷盘能力,cache 的脏页比例上升。超过 target 后后台淘汰开始追赶,超过 trigger 后应用线程亲自参与淘汰,单次写要等磁盘。写入变慢导致连接不释放,connections.current 上涨、queues.execution 堆积;应用侧超时重试,又带来更多写入。CPU 可能不高,磁盘 await 和脏页比例才是先兆。

链路二:复制延迟超过 oplog 窗口 → 从节点追不上 → 主节点压力和切换风险。 从节点落后太多,oplog 的旧记录被新写入覆盖,从节点无法增量追赶,只能进入 initial sync。initial sync 会全量拉数据、建索引,期间持续占用主节点和网络;多个从节点同时重同步时,主节点压力更大。同时,多数派提交点被最慢的从节点拖住,主节点写入延迟上升。等 rs.status() 显示 RECOVERING 时,窗口通常已经错过,真正的预警是「lag 增长速度超过 oplog 窗口的消耗速度」。

最小上手 ​

javascript
// mongosh,6.0+
db.serverStatus().connections
db.serverStatus().opcounters
db.serverStatus().queues
const c = db.serverStatus().wiredTiger.cache;
({
  used: c["bytes currently in the cache"],
  max: c["maximum bytes configured"],
  dirty: c["tracked dirty bytes in the cache"],
  read: c["pages read into cache"],
  written: c["pages written from cache"],
  blocked: c["checkpoint blocked page eviction"]
})

// 长操作、复制状态、checkpoint 耗时
db.currentOp({ active: true, secs_running: { $gt: 5 } })
rs.status().members.map(m => ({ name: m.name, state: m.stateStr, health: m.health }))
rs.printReplicationInfo()
rs.printSecondaryReplicationInfo()
db.serverStatus().wiredTiger.transaction["transaction checkpoint most recent time (msecs)"]

// profiler:level 1 只记超过 slowms 的操作,level 2 记录全部,开销明显
db.setProfilingLevel(1, { slowms: 100 })
db.system.profile.find().sort({ ts: -1 }).limit(5)
db.setProfilingLevel(0)
bash
mongostat --uri "mongodb://user:pass@host:27017/?authSource=admin" 1
mongotop --uri "mongodb://user:pass@host:27017/?authSource=admin" 5

Prometheus 用 mongodb_exporter 抓取(指标名以 exporter 版本为准):

yaml
scrape_configs:
  - job_name: mongodb
    static_configs:
      - targets: ["mongodb-exporter:9216"]

生产动作 ​

起点阈值,按基线校准:

指标预警告警处置
connections.available低于上限 20%低于 10% 或新连接被拒查长操作与连接池,先止血再谈扩容
queues.execution / currentQueue持续大于 0持续上涨且业务延迟升高找阻塞源,kill 长操作或限流
cache 脏页比例> 5–10%接近 eviction_dirty_trigger查写入突增与磁盘吞吐
checkpoint 耗时超基线 2 倍持续超基线且出现 blocked eviction降写入、查磁盘、调 cache 与刷盘
复制 lag> 10s> 30s,或超过 oplog 窗口的一半查从节点负载、网络、主节点写入量
oplog 窗口小于最长维护/断连时间的 2 倍小于业务可接受恢复时间调大 oplog,并降低写入峰值
asserts.regular / warning—任何持续增长按数据一致性问题处理,先保全备份
磁盘空间 / await剩余 < 20% 或 await 明显高于基线剩余 < 10% 或 IO 持续饱和清归档、扩盘、拆热点写入
docsExamined / nReturned> 100> 1000 或出现 COLLSCAN补索引、改查询、避免内存排序
主节点状态 / FCV发生切换无主、节点 health 异常、FCV 不一致查选举、网络、版本升级步骤

副本集和分片的关注点不同:副本集看成员 stateStr/health、lastCommittedOpTime、写关注 wtimeout 和 lag 与窗口的比例;分片还要看 mongos 的连接与路由、config server 健康、chunk 分布和 jumbo chunk、balancer 是否在迁移。迁移期间的负载升高是正常现象,别和故障混为一谈。

处置顺序建议「先止血、再根因」:

  1. 连接数:先确认是池配置还是操作变慢;kill 长操作、限流,扩容连接上限只能短时缓解。
  2. oplog/复制:确认 lag 和窗口,避免拖到 initial sync 或被迫切换;必要时先降写入压力。
  3. cache:看脏页比例和应用线程淘汰计数,判断写是不是在等磁盘。
  4. 磁盘:看 await、IOPS、空间和 checkpoint 耗时,根因通常在这一层。
  5. 慢查询:用 profiler 和 explain 定位 COLLSCAN、扫描放大、排序溢出,补索引或改查询防复发。

边界 ​

MongoDB 的强项是文档模型灵活、读写路径短、原生分片;代价是跨文档事务和关联查询弱,cache 与 oplog 都是有上限的资源。这决定了监控重点不是「会不会丢一条文档」,而是脏页、checkpoint、oplog 窗口和磁盘延迟;也决定了它不适合把关系型的强事务负载硬搬过来。

维度适合不适合
数据量单机到 TB 级,能按分片键水平扩展需要大量跨集合强关联和复杂多表事务
一致性可接受最终一致读,用写关注换持久性要求跨文档强一致且低延迟的核心账务
查询形态按文档/索引点查、聚合、范围查询、地理查询大量多表 join、复杂报表 SQL
团队成本能接受 schema 演进、愿意做索引治理和 explain希望零 schema 治理、没人维护索引

几个容易误判的地方:

  • cache 不是越大越好:默认约为「(内存 − 1GB) 的 50%」或 256MB 中较大者(以官方文档为准),调大要同步考虑容器 limit 和操作系统页缓存;cache 用满不是故障,脏页和磁盘等待才是。
  • profiler 有开销:level 2 会把每条操作写进 system.profile,明显增加延迟和 IO;level 1 也有写入成本。定位完就关掉,用慢日志和采样代替长期开启。
  • mongostat 是采样:默认 1 秒一行,第一行往往是从启动到现在的累计平均,不能拿来判断瞬时状态;qr|qw、ar|aw 和 % dirty 要结合业务延迟看,采样间隔太长会漏掉尖刺。
  • 分片均衡别误判:chunk 迁移、balancer 运行、目标 shard 负载上升都是设计内行为;要看迁移是否卡住、jumbo chunk 是否无法分裂,而不是看到迁移就报警。
  • 阈值随业务变化:延迟敏感业务和离线分析集群的警戒线完全不同,表里的数字只是起点。

相关:02-存储模型与WiredTiger、05-副本集与分片、08-MongoDB生产踩坑、99-生产检查清单。

讲清楚 ​

MongoDB 监控要分层:主机看磁盘和内存,进程看连接、队列、cache 脏页、checkpoint 和 asserts,复制与分片层看 lag、oplog 窗口和 chunk 分布,业务层确认用户是否已经受影响。它的强项是文档模型和水平扩展,代价是 cache、checkpoint、oplog 这三处有上限,所以典型雪崩就两条:脏页刷不动导致写延迟和连接堆积;复制延迟超过 oplog 窗口导致从节点重同步,反过来压垮主节点。预警要放在脏页比例、checkpoint 耗时和 lag 与窗口的比例上。阈值只是起点,必须按自己的基线和业务超时校准。

把一门技术讲透到既懂也会用