不能靠 serverstatus 或 currentop 原生捕获 $group 阶段的“运行中”状态,必须结合会话活跃度、执行时间阈值和聚合管道结构做间接判断;因 $group 作为阻塞阶段不单独暴露为独立操作,currentop 仅显示整个 aggregate 的 secs_running,需通过 pipeline 是否含 $group/$sort、allowdiskuse、cache 状态等组合指标定位卡顿。

直接结论:不能靠 serverStatus 或 currentOp 原生捕获 $group 阶段的“运行中”状态,必须结合会话活跃度、执行时间阈值和聚合管道结构做间接判断。
为什么 currentOp 查不到正在执行的 $group?
MongoDB 的 currentOp 命令返回的是当前活跃操作(如查询、更新、命令),但聚合管道整体被视作一个原子操作,其内部阶段($match、$group、$sort)不单独暴露为独立 op。尤其当 $group 是阻塞阶段时,它会把上游所有文档收齐才开始计算,此时 currentOp 显示的仍是整个 aggregate 操作,且 secs_running 从管道启动开始计时——你看到的“长时间”,可能是卡在 $group,也可能是卡在前面的 $lookup 或磁盘排序。
常见错误现象:
– 在 currentOp 中发现一个 secs_running > 30 的 aggregate,但 command.pipeline 里没明显瓶颈阶段;
– executionStats 里 executionTimeMillis 很高,但 currentOp 不显示具体阶段耗时。
如何定位真正卡在 $group 的聚合?
关键不是“看到 $group”,而是“排除其他阶段 + 确认内存/阻塞特征”。实操建议如下:
- 用
db.currentOp({ "secs_running": { "$gt": 15 }, "command.aggregate": { "$exists": true } })拉出长时聚合会话 - 对每个结果,检查
command.pipeline是否含$group、$sort(二者都是典型阻塞点) - 重点看
command.allowDiskUse是否为true:若开启且secs_running持续增长,大概率是$group正在刷磁盘(WiredTiger cache 不足或分组键基数过高) - 对比
serverStatus.metrics.record.moves和wiredTiger.cache.*:若 cache dirty > 80% 或 moves 飙升,说明$group输出大量中间数据,触发频繁 page out
监控告警该配哪些指标?
不要只盯单个命令,要建立组合判断逻辑:
- 告警条件 1:
currentOp.secs_running > 30且command.pipeline含$group→ 触发“潜在 $group 卡顿”预警 - 告警条件 2:
serverStatus.metrics.commands.aggregate.total每分钟突增,但serverStatus.opcounters.command无对应增长 → 可能是大量短时聚合被$group拖慢,积压成队列 - 告警条件 3:
replSetGetStatus.members[n].health == 0且同时currentOp中出现多个长时$group→ 副本集主节点资源被聚合占满,影响复制延迟
注意:Prometheus 抓取 mongodb_exporter 时,mongodb_mongod_op_counters_total{op="aggregate"} 是总量,需配合 rate() 和 mongodb_mongod_current_operations{state="active",type="query"} 做衍生判断。
为什么副本集场景下 $group 更容易出问题?
副本集里主节点承担全部写入和聚合读请求,而从节点默认不处理聚合(除非显式指定 readPreference=secondary)。这意味着:
- 所有带
$group的分析类查询都打到主节点,CPU 和内存压力集中 - 若主节点同时在做 oplog 复制 +
$group计算,wiredTiger.cache.maximum_bytes_configured不足时,$group会抢占 cache,导致复制延迟升高 - 从节点无法分担
$group负载,不像分片集群可将$group下推到各分片本地执行
真正难处理的不是“怎么查到 $group”,而是“查到了之后,你没法把它挪到别的节点上跑”。所以副本集监控 $group,本质是在监控主节点的资源饱和度边界。











