副本集连接数爆满主因是客户端连接池失控与慢查询阻塞连接未释放,需调优connectionsperhost、maxconnectionidletimems等参数,并排查>500ms慢查询及连接泄露。

副本集连接数爆满,八成不是 MongoDB 本身扛不住,而是客户端连接池失控 + 慢查询卡住连接没释放。别急着扩容或重启,先盯住 connectionsPerHost、maxConnectionIdleTimeMS 和慢日志里那些 query 耗时超 500ms 的操作。
Java 驱动连接池参数调得太猛
默认 connectionsPerHost=100 × threadsAllowedToBlockForConnectionMultiplier=5 = 单实例建 500 连接,副本集里哪怕只连一个 primary,也极易打满 mongos 或 replica set 的 maxConns(默认 819)。更糟的是,老版本驱动不设 maxConnectionIdleTimeMS,空闲连接永不回收。
- 把
connectionsPerHost改成 20~50,够多数中等 QPS 业务用 -
threadsAllowedToBlockForConnectionMultiplier设为 2 或 3,避免线程排队时“预占”大量连接 - 显式配置
maxConnectionIdleTimeMS=60000(60 秒),4.x+ 驱动才默认启用该机制,但必须写出来才生效 - 确认驱动版本 ≥ 4.3 —— 低于 4.0 的驱动对空闲回收支持不稳,容易假死连接
Node.js 驱动的 poolSize 是全局值,不是 per-host
很多人误以为 poolSize: 100 是每个 replica set 成员开 100 连接,实际是整个 MongoClient 实例总共最多 100 连接。设太大,所有节点共享这 100 个连接,反而导致争抢;设太小(比如默认 5),高并发下直接抛 MongoWaitQueueFullException。
- 生产环境建议设
poolSize: 10~20,配合重试逻辑比盲目堆连接更稳 - 务必加
minPoolSize: 5,避免低峰期连接全被回收,突增流量时建连延迟拉高 P99 - 禁用
autoReconnect: true(v4.0+ 已弃用),改用 driver 自带的 heartbeat + server selection 机制
慢查询让连接卡在 QUERY 状态不释放
连接数监控显示持续高位,但 netstat -an | grep :27017 | wc -l 和 db.serverStatus().connections.current 数值接近,说明连接真正在干活,不是 TIME_WAIT 堆积。这时要查 system.profile 里 millis > 500 的记录。
- 执行
db.setProfilingLevel(1, { slowms: 500 })开启 profiling(无需重启) - 查最耗时的查询:
db.system.profile.find({ millis: { $gt: 500 } }).sort({ millis: -1 }).limit(5) - 重点关注含
$lookup、未加索引的find({ status: "pending" })、或sort()后没 limit 的聚合 - 用
explain("executionStats")看executionTimeMillis和nReturned是否严重失衡
连接泄露常藏在异步回调或异常分支里
连接池参数调得再合理,只要代码里漏掉 client.close() 或 session.endSession(),连接就会一直挂在 ESTABLISHED 状态。尤其注意 try-catch 后没兜底释放、Promise.allSettled 里部分失败后忽略清理、Lambda 函数冷启动复用 client 实例但没做单例控制。
- Java:用 try-with-resources 包裹
MongoClient,或确保 finally 块调client.close() - Node.js:全局单例
const client = new MongoClient(uri, { poolSize: 10 }),应用生命周期内只 init/close 一次 - Go(mgo):检查是否漏掉
session.Close(),特别是session.Copy()后未 close 的副本 - 用
mongostat --host rs0/localhost:27017观察conn列是否缓慢爬升且不回落
真正难处理的从来不是参数数字,而是连接在哪儿卡住、为什么卡住、谁在用它——db.currentOp({ secs_running: { $gt: 30 } }) 比任何配置都更能告诉你此刻发生了什么。











