分片集群连接池耗尽主因是客户端配置失当:java驱动需调优connectionsperhost(20~50)和threadsallowedtoblockforconnectionmultiplier(2~3),显式配置maxconnectionidletimems=60000;node.js驱动poolsize应设为10左右,非per-host;事务必须确保endsession()调用,maxpoolsize应按并发事务数×1.5估算,而非盲目增大;三步定位法(netstat、connpoolstats、net.maxincomingconnections)可精准识别瓶颈层。

分片集群里连接池耗尽,八成不是 mongos 或 mongod 真的扛不住,而是客户端驱动参数没调、连接没回收、事务没结束——直接改 maxPoolSize 只会把问题从 mongos 推到后端 shard 上。
Java 驱动里 connectionsPerHost 和 threadsAllowedToBlockForConnectionMultiplier 怎么配
这两个参数共同决定单实例向一个 mongos 最多建多少连接。默认 connectionsPerHost=100 × threadsAllowedToBlockForConnectionMultiplier=5 = 500 连接/实例,20 台服务就轻松压爆 mongos 的连接上限。
-
connectionsPerHost建议设为20~50,别碰默认 100; -
threadsAllowedToBlockForConnectionMultiplier改成2或3,避免线程排队时疯狂占连接; - 确认驱动版本 ≥ 4.x,并显式配置
maxConnectionIdleTimeMS=60000,否则空闲连接不会自动释放; - 旧版驱动(如 3.12)不支持
maxConnectionIdleTimeMS,必须升级才能生效。
Node.js 驱动中 poolSize 是全局池大小,不是 per-host
poolSize 在 Node.js 的 mongodb 驱动里是 MongoClient 实例级的总连接数上限,不是每个 mongos 地址单独一份。设成 100 就真只开 100 条连接,不管 seed 列表里写几个地址。
- 多数业务
poolSize: 10起步足够,别一上来就写100; - 搭配
minPoolSize: 5防冷启动抖动; -
waitQueueTimeoutMS必须设,推荐3000~5000,比 P99 事务耗时略高即可; - 手动启事务时(非
withTransaction()),务必确保session.endSession()被调用,否则连接永不归还。
事务卡住连接池时,maxPoolSize 不是越大越好
事务开启后,连接被会话独占,直到 commitTransaction() 或显式 endSession()。如果某类事务平均耗时 800ms、QPS 是 150,那同时活跃事务约 120 个——maxPoolSize 设成 180 就够用,拉到 500 反而让 mongos 后端连接翻倍打满。
- 先用
db.currentOp({secs_running: {$gt: 1}})找出长事务,再算并发基数; -
minPoolSize设为maxPoolSize的 10%~20%,比如maxPoolSize: 180→minPoolSize: 20; - 聚合查询含
$lookup或跨分片时,实际耗时可能翻倍,得按监控数据重估; -
waitQueueTimeoutMS触发时,务必在日志里记下session.id和堆栈,不然没法定位是哪段逻辑漏了endSession()。
怎么快速判断连接到底卡在哪一层
别一上来就改配置或重启。先跑三步命令定位瓶颈层:
- 客户端侧:
netstat -anp | grep :27017 | wc -l看本机连出去的连接数是否异常高; - mongos 侧:
db.runCommand({connPoolStats: 1})查各 shard 的inUse是否长期等于maxConnsPerHost; - shard 侧:检查
net.maxIncomingConnections是否 ≥ mongos 的maxConnsPerHost,否则会出现connection refused by peer; - 若 mongos 的
conn数持续 > 300 且mem持续涨,大概率是游标没消费完或空闲连接没回收,不是连接池大小问题。
真正难调的从来不是参数数字,而是那些没被 try/finally 包裹的 session.endSession(),和 DNS 解析失败后卡死 20 秒才报错的初始化流程。











