聚合查询在主节点易失控因默认执行且$group等操作耗资源;需用maxtimems和allowdiskuse协同控制,优先加$limit;可读写分离至从节点,并调优wiredtiger缓存与读关注配置。

为什么聚合查询在主节点上容易失控
聚合查询(aggregate())默认在主节点执行,尤其当管道中含 $group、$sort、$lookup 或未加 $limit 时,会大量占用内存和 CPU。WiredTiger 引擎对单个操作的内存无硬性上限,但若聚合中间结果集超过可用 RAM,就会触发频繁磁盘换页(表现为 mongostat 中 faults 持续非零),拖垮整个主节点响应能力。
用 maxTimeMS 和 allowDiskUse 控制执行边界
这两个参数必须配合使用,单独设一个效果有限:
-
maxTimeMS是超时兜底:强制中断运行超时的聚合,避免长任务卡死线程。例如db.orders.aggregate([...], { maxTimeMS: 30000 })表示最多跑 30 秒 -
allowDiskUse: true是资源让步:允许聚合在内存不足时写临时文件到磁盘,防止因 OOM 被内核 kill。但它不降低 CPU 占用,反而可能因 I/O 加重负载 - 关键点:如果业务能接受部分结果,优先加
$limit在管道前端;若必须全量处理,再开allowDiskUse,且务必配maxTimeMS
通过 readPreference 把聚合分流到从节点
不是所有聚合都必须在主节点跑。只要不涉及写操作(如 $out、$merge),且业务能容忍少量同步延迟,就可以把读密集型聚合迁移到从节点:
- 驱动层设置
readPreference=secondary(或nearest),连接字符串里加&readPreference=secondary - 注意:若聚合中用了
$facet或多阶段$lookup,仍可能因数据局部性拉取大量文档,导致从节点内存压力上升 - 验证是否生效:在从节点上执行
db.currentOp({ "secs_running": { "$gt": 2 } }),看ns和query是否匹配你的聚合命令
限制聚合内存用量的底层配置(需重启)
WiredTiger 自身不提供 per-query 内存限制,但可通过全局参数压制聚合类操作的资源胃口:
- 在
mongod.conf的storage.wiredTiger.engineConfig下设cacheSizeGB:例如设为16(总内存 64GB 机器),可防聚合吃光全部 cache,但过小会导致整体性能下降 - 禁用旧版本快照(若不用 majority read concern):在
replication段加enableMajorityReadConcern: false,可省下 15–25% 内存,让聚合更“轻量” - 真正起效的前提是:聚合操作本身没写错(比如漏索引、漏
$match提前过滤),否则参数再严也压不住逻辑缺陷
最常被忽略的一点:聚合是否真的需要在副本集主节点执行——很多报表类聚合,只要加了 readPreference=secondary 并确认从节点同步延迟 maxTimeMS 调参,先看它该不该在这儿跑。











