mongos连接池耗尽表现为应用端connection refused或timeout,但mongos自身资源正常;其根本原因是客户端连接数×shard数导致后端连接爆炸,因mongos为每次请求涉及的每个shard单独建连,且无硬性连接限制。

mongos 连接池耗尽的典型症状
应用端报 connection refused 或 timeout waiting for connection,但 mongos 进程本身 CPU 和内存正常;用 db.currentOp() 查不到大量慢操作;netstat -an | grep :27017 | wc -l 显示 mongos 到后端 shard 的连接数远超预期——比如客户端只开 50 个连接,mongos 却维持了 800+ 到各 shard 的连接。
为什么客户端连接数 × shard 数 = mongos 实际连接爆炸
mongos 不复用连接:每个客户端连接在路由时,会为**本次请求涉及的每个 shard**(哪怕只查一个 collection)单独建立或复用一条到该 shard 的连接。如果集群有 8 个 shard,客户端开了 100 个连接,极端情况下 mongos 可能撑起近 800 条后端连接(尤其跨分片查询、chunk 迁移期间)。
-
maxPoolSize在 driver 层控制客户端到 mongos 的连接上限,但它对 mongos 内部到 shard 的连接完全无效 - mongos 自身没有类似
maxConnPerHost的硬限制,只靠connPoolMaxSize(默认 1000)软控,超限后新请求会被阻塞或失败 - 分片键设计不合理(如全表扫描、范围查询覆盖多数 chunk)会加剧连接分散
快速缓解:从 mongos 配置和 driver 参数双端压降
不是调大连接数,而是减少“连接乘数”的触发条件。
- 在 mongos 启动时加参数:
--setParameter connPoolMaxSize=300(根据 shard 数反推:300 ÷ shard 数 ≈ 单 shard 平均连接数,留余量) - 客户端 driver 必须显式设置
maxPoolSize,Node.js MongoDB Driver 示例:new MongoClient(uri, { maxPoolSize: 30 });Python PyMongo 同理:maxPoolSize=30 - 禁用
minPoolSize(除非你真需要冷启动保活),它会让 mongos 提前建一堆闲置连接 - 检查是否误启了
retryWrites=true且写操作频繁——重试会新建连接,而非复用原连接路径
根治依赖:分片键 + 查询模式 + 连接生命周期协同优化
连接池问题本质是流量分布问题。不改数据模型和查询习惯,调参只是拖时间。
- 避免用
_id(ObjectId)做分片键——其随机性导致查询必然打散到多个 shard - 聚合查询加
$match尽量前置,且条件中必须含分片键,否则 mongos 无法路由,被迫 fan-out 到全部 shard - 短连接场景(如 Serverless 函数)务必用
client.close(),别依赖 GC;长连接服务要监控client.topology.s.servers中各 mongos 节点的连接状态 - 升级 mongos 到 6.0+,启用
sharding.connectionPoolRefreshIntervalMS(默认 60000),让空闲连接更积极回收
真正麻烦的是那些已经上线、分片键改不动、又不敢动查询逻辑的老服务——这时候得靠连接池指标埋点(如 serverStatus().connections + shardConnPoolStats)做动态熔断,而不是等 mongos 挂了才反应过来。

















