cpu高主因是聚合触发大量文档扫描或内存溢出,需通过system.profile/慢日志抓取含aggregate命令、collscan/ixscan及高docsexamined的操作,并用explain("executionstats")验证nreturned远小于totaldocsexamined、memoryusagebytes超限等真实开销。

直接看 system.profile 和慢日志,配合 explain("executionStats"),才能定位聚合管道真实消耗在哪——CPU高往往不是管道本身“慢”,而是它触发了大量扫描或内存溢出。
怎么从慢日志里抓聚合的CPU热点
聚合操作不会单独标记为“聚合”,它在日志里就是普通命令,但有明显特征:
- 日志中出现
command字段包含aggregate,且planSummary里带COLLSCAN或IXSCAN后跟大量docsExamined(比如 >10000) - 高频出现
saslStart错误,说明短连接认证开销正在放大 CPU 负载,尤其在聚合前频繁重连时 -
durationMillis高 +cpuNanos(如果开启详细 profiling)占比异常,说明单次聚合线程占满 CPU 时间片
为什么 allowDiskUse: true 可能反而让 CPU 更高
磁盘落盘不是“省 CPU”,而是把内存压力转嫁给 I/O 和序列化/反序列化——尤其当 $group 或 $sort 阶段写临时文件时:
- 每个落盘块都要做 BSON 编解码,这部分是纯 CPU 操作
- 如果磁盘本身慢(比如云盘 IOPS 不足),会导致聚合卡在等待 I/O,线程阻塞+重试,进一步抬高 CPU 等待时间
-
usedDisk: true出现在explain结果里,但没配maxTimeMS,容易让长耗时聚合持续霸占线程
用 explain("executionStats") 看清内存和扫描真实开销
别只看总耗时,重点盯这几个字段:
-
executionStats.nReturned:实际返回多少文档——如果远小于executionStats.totalDocsExamined,说明过滤逻辑太靠后(比如$match放在$group后) -
executionStats.memoryUsageBytes(MongoDB 6.0+):该阶段实际用了多少内存;超过 100 MB 且没设allowDiskUse,会直接报错 -
executionStats.executionTimeMillisEstimate和executionStats.executionTimeMillis差值大,说明计划器预估严重失准,可能索引失效或统计信息陈旧
执行示例:
db.orders.aggregate([
{ $match: { status: "completed", createdAt: { $gte: ISODate("2025-01-01") } } },
{ $group: { _id: "$userId", total: { $sum: "$amount" } } }
], { explain: "executionStats" })
监控时最容易忽略的点
聚合的资源消耗不是静态的——它随数据分布、索引覆盖度、并发请求数动态变化。最常被漏掉的是:
- 没区分
mongos和shard节点的 CPU:mongos处理路由和结果合并,聚合含$lookup或跨分片$sort时,它的 CPU 可能比 shard 还高 - 把
resident memory当成“MongoDB 用了多少内存”:其实它包含操作系统页缓存,真正影响聚合性能的是workingSet(活跃数据集)是否能装进 RAM - 忽略
pipeline阶段顺序对内存峰值的影响:比如$unwind后立刻$group,可能瞬间放大内存占用数倍,而加个$limit在前就能压住











