allowDiskUse: true 必须作为聚合顶层选项而非pipeline阶段传入,且需配合cursor batchSize避免mongos内存溢出;大字段须精准投影,$sort/$group等阶段需前置强过滤,临时目录须显式指定并确保空间充足。

为什么 allowDiskUse: true 在分片集群里常失效
很多人加了 allowDiskUse: true 却仍看到 mongos OOM,根本原因是它被当成了 pipeline 阶段写进聚合数组里,比如:[{ $group: { ... } }, { allowDiskUse: true }]——这完全无效。它必须是客户端发起聚合请求时的**顶层选项**,和 pipeline 并列传入。
更隐蔽的问题是:即使传对了,如果没配 cursor: { batchSize: 1000 },mongos 仍可能把全部中间结果一次性拉进内存再返回,disk use 形同虚设。
-
allowDiskUse是驱动层参数,不是 pipeline 操作符 - Node.js 驱动中要写成
collection.aggregate(pipeline, { allowDiskUse: true, cursor: { batchSize: 1000 } }) - Python PyMongo 同理:
collection.aggregate(pipeline, allow_disk_use=True, cursor={'batch_size': 1000}) - Shell 中用
db.collection.aggregate(pipeline, { allowDiskUse: true }),但 shell 不支持游标批大小控制,高风险
大文本字段怎么避免“偷偷搬砖进内存”
只要 pipeline 里任何一处出现 content: 1 或 $project: { content: 1 },哪怕后续立刻 $unset 或根本没用到,mongos 就会从所有分片把完整 content 字段内容取回来——几十 KB × 几万文档 = 内存瞬间起飞。
真正安全的做法是:在 pipeline 最开头就做精准投影,且只留真正需要参与后续计算的字段。
- 错误写法:
{ $project: { title: 1, content: 1, author: 1 } }, { $group: { _id: "$author", count: { $sum: 1 } } } - 正确写法:
{ $project: { author: 1 } }, { $group: { _id: "$author", count: { $sum: 1 } } } - 如果必须统计含关键词的文档数,用
$regexFind+$cond在投影后做轻量判断,别拖整段文本进来 - 对
text索引字段,优先用$text查询替代$regex全字段扫描
哪些聚合阶段在 mongos 层最吃内存
mongos 不执行存储,但它要协调、合并、排序、去重所有分片返回的结果。以下阶段会让 mongos 成为内存黑洞:
-
$sort:必须把所有分片的候选文档拉到 mongos 才能全局排序;没索引支撑时必爆内存 -
$group(尤其跨分片):各分片先局部 group,mongos 再 merge 多个中间结果;若_id分布极不均衡,某一个 key 的中间结果就可能占满内存 -
$lookup(无 pipeline 过滤):触发广播式查询,每个分片都向被 join 集合全量扫描,中间数据量指数级膨胀 -
$facet:每个 facet 分支独立执行,内存占用是各分支之和
规避原则:能下推到分片执行的尽量下推;$sort 和 $group 前必须有强 $match 过滤;$lookup 必须带 pipeline 且用分片键过滤目标集合。
临时文件路径和磁盘空间容易被忽略
allowDiskUse: true 默认把临时文件写在系统临时目录(如 /tmp),但分片集群中 mongos 进程可能运行在内存小、/tmp 分区只有几 GB 的管理节点上——磁盘写满直接卡死。
必须显式指定可靠路径,并确保该路径所在磁盘有足够空间(建议 ≥ 聚合预期最大中间结果的 2 倍):
- Linux 下启动 mongos 时加参数:
--tempPath /data/mongos-temp - 或在配置文件
/etc/mongos.conf中设置:systemLog: destination: file; path: /var/log/mongodb/mongos.log; tempPath: /data/mongos-temp - 验证是否生效:
ps aux | grep mongos看启动参数,或查日志里是否有Using temporary directory提示 - 注意权限:mongos 进程用户(如
mongod)必须对tempPath目录有读写权限
临时文件不自动清理,长期运行的 mongos 要配合定时任务 find /data/mongos-temp -name "mmap-*" -mmin +60 -delete(慎用,先测试)。


















