2. MongoDB关键运行指标解析
MongoDB 的监控面板上指标很多,但真正决定“现在能不能扛住、接下来会不会出问题”的,往往集中在少数几类:连接、操作计数、队列、游标、复制延迟和缓存。理解它们的关键,不是背名字,而是知道每个数字背后对应哪条资源链路,以及它升高或降低时该往哪里看。
连接数:先分清当前连接、可用连接与连接创建速率
连接数反映客户端与 mongod/mongos 之间已建立的会话数量。生产上最常看三个值:connections.current(当前活跃连接)、connections.available(还能接受多少新连接)、connections.totalCreated(累计创建连接数)。前两者决定“还有没有余量”,第三个的增速决定“连接是否在被频繁重建”。
如果 current 持续贴近 available + current 的上限,新请求会拿不到连接而超时。但更隐蔽的问题是连接创建速率过高:应用没有使用连接池,或池配置过小、请求频繁新建连接,会导致 totalCreated 快速上涨,同时伴随认证、线程创建开销。判断方法是对 totalCreated 做差分,例如每 10 秒采样一次,若稳定在每秒几十次以上,就应检查应用连接池的 maxPoolSize、minPoolSize 与空闲回收策略,而不是单纯调大 MongoDB 的 maxIncomingConnections。
操作计数器:用 opcounters 看负载结构,而不是只看总量
opcounters 按操作类型统计:insert、query、update、delete、getmore、command。它回答的是“这台实例在忙什么”。例如 query 高而 insert/update 低,说明以读为主;update 高且伴随大量 getmore,可能是批量扫描或大结果集。getmore 尤其值得关注,它表示游标在分批取回剩余数据,若 getmore 长期偏高,通常意味着查询返回结果集过大或游标未及时关闭。
实际分析时不要只看累计值,而要看单位时间增量。示例:某实例 60 秒内 query 从 1,200,000 增至 1,260,000,则 query 速率约为 1000 次/秒;同期 getmore 从 8,000 增至 20,000,getmore 速率约 200 次/秒。后者占比明显偏高,应优先检查是否存在未加限制的 find()、缺少索引导致的全表扫描,以及应用是否在遍历大游标。
队列:queued 与 active 是判断“是否被压住”的直接信号
MongoDB 的队列指标主要看 globalLock.currentQueue.total、globalLock.currentQueue.readers、globalLock.currentQueue.writers,以及 WiredTiger 的 concurrentTransactions.read/write 中的 out(排队数)和 available(可用并发票据)。
读队列升高通常说明并发读太多或某个查询太慢;写队列升高则往往与写冲突、锁等待、磁盘写入能力不足有关。WiredTiger 的 available 降到 0 表示读或写票据已耗尽,后续请求只能排队。此时应结合慢查询日志和 db.currentOp() 找到占用票据时间最长的操作,而不是盲目增加并发。
游标:open 数量与超时是内存与连接泄漏的预警
metrics.cursor.open.total 表示当前打开的游标数,timedOut 表示因空闲超时被清理的游标数。游标本身不是错误,但 open 持续增长、timedOut 同步上升,说明应用创建了游标却没有及时耗尽或关闭。常见原因是分页查询未限制、聚合管道返回大结果集、或客户端异常退出后游标残留。
生产上可设置 cursorTimeoutMillis(默认约 10 分钟)控制空闲游标回收。若 open 长期高于数百且与业务量不匹配,应检查应用是否在循环中反复 find() 而不复用,或是否对同一集合反复执行未关闭的 aggregate()。
复制延迟:用 optime 差值判断从节点是否“落后”
复制延迟的核心是主从 optime 的时间差。在副本集中,可通过 rs.status() 查看各成员的 optimeDate,主节点与从节点的差值即为延迟。另一个重要指标是 replSetGetStatus 中的 members[n].optime 与 lastCommittedOpTime。
延迟升高常见于:从节点磁盘写入慢、网络带宽不足、主节点写入量突增、从节点执行长查询或备份。若延迟持续超过业务可接受范围(例如 10 秒),读偏好为 secondary 的应用会读到旧数据。此时应检查从节点 db.serverStatus().wiredTiger 的写入队列、网络往返时间,以及是否有大事务或批量写入。
缓存使用:WiredTiger cache 的“脏页比例”比使用率更关键
WiredTiger 缓存指标中,cache.bytes currently in the cache 表示已用缓存,cache.maximum bytes configured 是上限(默认约为物理内存的 50%)。但真正影响性能的是 tracked dirty bytes in the cache 与 bytes read into cache、bytes written from cache。
当脏页比例持续超过 20%,WiredTiger 会触发更频繁的 eviction,表现为写入延迟上升、队列增长。若 bytes read into cache 远高于 bytes written from cache,说明读多写少,缓存命中较好;反之则可能写入压力大。生产上应关注 cache.eviction 相关计数是否快速增长,以及 pages read into cache 是否因缓存不足而升高。
把指标串起来看:一次写入变慢的排查路径
假设某实例写入延迟上升。先看 opcounters.update 是否突增,再看 globalLock.currentQueue.writers 与 WiredTiger concurrentTransactions.write.out 是否排队。若排队明显,继续看 cache.tracked dirty bytes 是否超过缓存上限的 20%,以及 cache.eviction 是否快速增长。若脏页高、eviction 频繁,说明写入压力已超过缓存回写能力,应检查磁盘 IOPS 与写入批量大小。若队列不高但复制延迟同步上升,则问题可能出在从节点回放速度,而非主节点本身。
容量规划中的指标基线
做容量规划时,至少要为每类指标建立基线:连接数峰值、opcounters 各操作速率、队列最大值、游标 open 峰值、复制延迟 P95、缓存脏页比例。以连接数为例,若业务峰值 current 为 800,available 为 200,则余量仅 20%,扩容或调大连接上限应提前进行。以复制延迟为例,若 P95 已接近 5 秒,而业务要求 secondary 读延迟不超过 2 秒,则需优化从节点磁盘或调整读偏好。
这些指标不是孤立的:连接数影响并发,并发影响队列,队列影响操作延迟,操作延迟又反过来影响游标存活时间与复制延迟。理解它们之间的传导关系,才能在故障发生前做出正确判断,而不是在告警响起后才逐个试错。