应复用 mongoclient 实例并显式配置连接池参数:设 minpoolsize: 1、maxpoolsize: 5、maxidletimems: 30000、serverselectiontimeoutms: 5000,避免每次函数执行新建连接池导致连接爆炸。

无服务器函数里反复 new MongoClient 会创建独立连接池
每次函数执行都调用 new MongoClient(),就会新建一个连接池(默认 maxPoolSize: 100),而无服务器平台(如 AWS Lambda、Vercel Edge Functions)通常不复用进程——冷启动时全新实例,热启动时也**不保证复用同一 Node.js 进程**。结果是:100 次并发请求 ≈ 100 个独立 MongoClient 实例 ≈ 最多 100 × 100 = 10,000 个连接直冲 mongos。
- Node.js 驱动的连接池是实例级的,不是全局单例;
require('mongodb').MongoClient每次new都隔离 - 无服务器环境没有稳定的“应用生命周期”,
process.on('SIGTERM')不可靠,client.close()很难被真正执行 - 即使函数执行完,TCP 连接可能滞留在 TIME_WAIT 状态,而平台底层容器尚未销毁,连接未释放
不设 minPoolSize 和 maxIdleTimeMS 会让空闲连接永远挂着
默认 minPoolSize: 0 + maxIdleTimeMS: 0(永不释放),意味着每次函数冷启建的连接,在函数“休眠”期间仍维持 ESTABLISHED 状态。你看到 netstat -an | grep :27017 | wc -l 持续上涨,基本就是这个原因。
-
maxIdleTimeMS: 0是默认值,不是“不限制”,而是“永不淘汰”——连接一旦建立,就卡死在池里 -
minPoolSize: 0导致低峰期连接数归零,但下次冷启又要重建,加重延迟,且无法缓解暴增问题 - 必须显式设置:
minPoolSize: 1(保底一个连接防重建) +maxIdleTimeMS: 30000(30 秒空闲即回收)
无服务器场景下 serverSelectionTimeoutMS 不设会导致请求卡死并堆积连接
无服务器函数有硬性超时(如 Lambda 默认 15 秒),若 MongoDB 连接失败后不快速失败,await client.connect() 会一直等,默认 serverSelectionTimeoutMS: 30000(30 秒),直接超出函数时限,触发平台强制终止——此时连接已发出但未关闭,变成孤儿连接。
- 务必把
serverSelectionTimeoutMS设为函数超时的 1/3 左右,例如 Lambda 设 90000ms(90 秒)就配serverSelectionTimeoutMS: 30000;设 5000ms 更稳妥 - 同时配
connectTimeoutMS: 5000和socketTimeoutMS: 10000,防止 DNS 卡住或 TLS 握手拖慢 - 别依赖
useUnifiedTopology: true自动兜底——它只优化发现逻辑,不缩短超时时间
正确做法:复用客户端实例 + 显式控制生命周期
无服务器函数不是传统服务,不能靠“进程常驻”管理连接。唯一可靠方式是:在模块顶层创建并导出单个 client,让运行时尽可能复用;并在函数退出前尝试关闭(非强制,但要写)。
- 在文件顶层
const client = new MongoClient(uri, { minPoolSize: 1, maxPoolSize: 5, maxIdleTimeMS: 30000, serverSelectionTimeoutMS: 5000 }) - 首次
await client.connect()后缓存db实例(如let db+if (!db) db = client.db(...)) - 在 handler 结尾加
if (process.env.NODE_ENV === 'development') await client.close()—— 生产中不关更安全,因平台可能已回收上下文 - 绝对不要在 handler 内部
new MongoClient或mongoose.connect(),那是连接爆炸的起点











