NestJS部署Lambda连接MongoDB时连接数过多问题求助
解决NestJS Lambda服务中Mongoose连接重复创建的问题
问题根源
- REQUEST作用域的配置服务:原
MongooseConfigService使用Scope.REQUEST,导致每次请求都会实例化该服务,触发createMongooseOptions重新生成连接配置,进而创建新的Mongoose连接。 - 错误的配置时机:
MongooseModule.forRootAsync在模块初始化阶段执行,此时还没有请求上下文,无法正确获取请求中的dbName;即使改为Scope.DEFAULT,也会因为初始化时无请求参数导致配置无效。 - 未复用连接:原方案没有对不同
dbName的连接或数据库实例进行缓存,每次请求都新建资源。
解决方案
方案1:复用底层连接,动态切换数据库(推荐)
利用Mongoose的useDb()方法,基于同一个基础连接切换不同的数据库,自动缓存数据库实例,避免重复创建TCP连接。
1. 创建连接管理器服务
import { Injectable } from '@nestjs/common'; import * as mongoose from 'mongoose'; @Injectable() export class MongooseDbManager { // 初始化默认基础连接(无特定dbName) private readonly baseConnection: mongoose.Connection; constructor() { this.baseConnection = mongoose.createConnection(process.env.MONGO_URL, { // 适配Lambda场景的连接池配置 poolSize: 5, maxPoolSize: 10, minPoolSize: 1, }); } // 根据dbName获取对应的数据库实例,useCache自动缓存 getDatabase(dbName: string): mongoose.Db { if (!dbName) { throw new Error('dbName is required'); } return this.baseConnection.useDb(dbName, { useCache: true }); } }
2. 在业务服务中使用动态数据库
import { Injectable } from '@nestjs/common'; import { Request } from 'express'; import * as mongoose from 'mongoose'; import { MongooseDbManager } from './mongoose-db.manager'; @Injectable() export class DataService { constructor(private readonly dbManager: MongooseDbManager) {} async fetchData(request: Request) { // 解析请求体 if (Buffer.isBuffer(request.body)) { request.body = JSON.parse(request.body.toString()); } const { db } = request.body; // 获取目标数据库实例 const targetDb = this.dbManager.getDatabase(db); // 获取模型(确保模型在数据库实例上注册) const YourModel = targetDb.model('YourModel'); // 执行数据库操作 return YourModel.find().limit(10).exec(); } }
3. 模块配置
移除原有的MongooseModule.forRootAsync配置,直接引入自定义的连接管理器:
import { Module } from '@nestjs/common'; import { MongooseDbManager } from './mongoose-db.manager'; import { DataService } from './data.service'; @Module({ providers: [MongooseDbManager, DataService], exports: [DataService], }) export class DatabaseModule {}
方案2:缓存不同dbName的独立连接
如果需要为每个dbName创建独立连接(资源消耗较大,非推荐),可以通过Map缓存已创建的连接:
import { Injectable } from '@nestjs/common'; import * as mongoose from 'mongoose'; @Injectable() export class MongooseConnectionManager { private readonly connections = new Map<string, mongoose.Connection>(); async getConnection(dbName: string): Promise<mongoose.Connection> { if (!dbName) { throw new Error('dbName is required'); } // 缓存中存在则直接返回 if (this.connections.has(dbName)) { return this.connections.get(dbName); } // 创建新连接并缓存 const connection = await mongoose.createConnection(process.env.MONGO_URL, { dbName, poolSize: 5, }); this.connections.set(dbName, connection); return connection; } }
Lambda场景注意事项
- 连接池配置:Lambda容器可能被复用,合理设置连接池大小(如
poolSize:5)避免资源浪费;容器销毁时连接会自动释放。 - 避免冷启动延迟:首次请求会创建连接,后续复用容器时直接使用已有的连接/数据库实例。
- 错误处理:添加连接异常捕获,处理连接断开等情况,必要时清除缓存重新创建。
内容的提问来源于stack exchange,提问作者Hamza Afridi
相关产品推荐
相关产品推荐

