maxtimems必须绑定角色生效,单次命令传参无效;需在admin库创建角色并注入,超时报错maxtimemsexpired(262);maxmemoryusagemb仅限制管道内内存,不控全表扫描;allowdiskusebydefault设false可防隐式落盘。

maxTimeMS 必须绑定角色,单次命令传参无效
很多人试过在 aggregate() 调用里加 { maxTimeMS: 3000 },发现业务账号还是能跑出 20 秒的慢聚合——这是因为该参数只对当次命令生效,驱动或 ORM(比如 Spring Data MongoDB)自动发起的聚合根本不会带这个选项。真正起作用的方式是把 maxTimeMS 写进角色定义里,由 mongod 在认证阶段强制注入。
注意两点:
• 必须在 admin 数据库中创建角色,不能在业务库执行 db.createRole()
• maxTimeMS 对所有聚合阶段统一生效,包括 $lookup、$facet 等隐式耗时操作
• 超时错误类型是 MaxTimeMSExpired(错误码 262),不是 QueryExceededTimeLimit
maxMemoryUsageMB 是防内存爆炸的关键,但只管“管道内”数据
maxMemoryUsageMB 从 MongoDB 4.4 开始支持,它才是真正卡住 OOM 的开关:设为 100,一旦某个 $group 或 $sort 阶段实测内存超限,立刻报错 Exceeded memory limit for $group, but didn't allow external sort。
但它有明确边界:
• 不拦截全表扫描本身——如果 $match 放在管道末尾,前面已经加载了全部 5000 万文档,maxMemoryUsageMB 压根不会触发
• 对未命中索引的 $lookup 无效,因为关联查询的内存开销发生在 JOIN 阶段前
• 它只限制“已进入聚合管道的数据”的处理内存,不是整个查询生命周期
allowDiskUse 和 allowDiskUseByDefault 容易混淆
线上误配 allowDiskUse: true 反而会让问题更隐蔽:它只是把内存换成了磁盘 I/O,$sort 或 $group 依然可能拖垮 IO 和连接数。真正的资源控制点是 allowDiskUseByDefault 这个服务器级参数:
- 设为
false(默认):任何超 100MB 的阶段直接报错Sort exceeded memory limit - 设为
true:默认允许落盘,但你仍需靠maxMemoryUsageMB把单个用户的总内存压到安全水位 - 二者不互斥——
allowDiskUseByDefault: true+maxMemoryUsageMB: 50才是合理组合:既防爆内存,又避免无脑落盘
验证角色限制是否真生效的三个动作
光创建角色不等于生效,必须走完这三步:
• 用目标账号登录,执行一个确定会超时的聚合,例如:db.orders.aggregate([{$group:{_id:null,c:{$sum:1}}}]),观察是否返回 MaxTimeMSExpired
• 查看 db.runCommand({connectionStatus: 1}) 输出里的 authInfo 字段,确认当前会话已应用目标角色
• 检查日志:开启 verbosity: 1 后,mongod 日志中出现 exceeded memory limit 或 max time expired 才算真实拦截
最容易被忽略的是:角色修改后,已有连接不会自动刷新权限,必须让客户端重连或重启应用连接池。











