NestJS+TypeORM多租户多数据库处理方案优化咨询
多租户数据库连接优化方案解析
当前方案的核心问题
你现在的实现每次请求都创建并初始化新的DataSource,这绝非最优解——数据库连接的建立、ORM元数据加载都是高开销操作,频繁执行会导致显著的性能损耗,高并发场景下甚至会引发服务雪崩。
最优优化方向:缓存已初始化的DataSource + 复用连接池
核心思路是为每个租户缓存对应的DataSource实例,避免重复创建,同时依托数据库自身的连接池复用物理连接,大幅降低资源消耗。
具体实现代码调整
在DatabaseService中添加租户DataSource缓存
用Map存储已初始化的DataSource,以租户数据库名作为key:private tenantDataSources = new Map<string, DataSource>();修改getDbConnForUser方法,优先复用缓存
先检查缓存中是否存在对应租户的DataSource,存在则直接返回;不存在再创建初始化并加入缓存:async getDbConnForUser() { // 保留原有用户校验逻辑 const user = this.utilityService.getUserFromRequestContext(); if (!user) throw new UnauthorizedException('Invalid User'); const subdomain = user.subdomain; const userSubdomains = await this.tenantService.findUserAndSubdomainsByEmail(user.email); if (userSubdomains.length === 0) throw new UnauthorizedException('Invalid User'); if (!userSubdomains.find(ud => ud.subdomain === subdomain)) { throw new UnauthorizedException('Forbidden Access'); } const tenant = await this.tenantService.getMasterTenantBySubdomain(subdomain); if (!tenant) throw new NotFoundException('Tenant not found'); // 优先从缓存获取 if (this.tenantDataSources.has(tenant.dbName)) { return this.tenantDataSources.get(tenant.dbName); } // 缓存不存在时创建新DataSource const newDataSource = new DataSource({ type: 'postgres', host: this.configService.get('TENANT_DB_HOST'), port: this.configService.get('DB_PORT'), username: this.configService.get('TENANT_DB_USERNAME'), password: this.configService.get('TENANT_DB_PASSWORD'), database: tenant.dbName, entities: [join(process.cwd(), 'dist/**/tenant/*.entity.js')], subscribers: [join(process.cwd(), 'dist/**/subscribers/*.subscriber.js')], synchronize: false, // 生产环境必须关闭 // 配置连接池参数,根据业务规模调整 poolSize: 10, maxQueryExecutionTime: 5000 }); await newDataSource.initialize(); this.tenantDataSources.set(tenant.dbName, newDataSource); return newDataSource; }关键注意事项
- 连接池配置:ORM的
poolSize需与PostgreSQL的max_connections参数匹配,避免超出数据库连接上限。 - 缓存清理:若存在租户删除场景,需从缓存中移除对应DataSource并调用
destroy()释放资源。 - 生产环境禁用synchronize:严格按照注释要求关闭,防止意外修改数据库结构。
- 连接池配置:ORM的
长期架构可选方向
当租户规模持续增长时,单租户单库模式的运维成本会上升,可考虑以下替代方案:
- Schema隔离:所有租户共用一个数据库,每个租户对应独立Schema,通过切换Schema实现隔离,无需维护多个DataSource。
- 行级隔离:所有租户数据存储在同一张表,通过
tenant_id字段区分,维护成本最低,但需严格控制权限并优化查询性能。
内容的提问来源于stack exchange,提问作者mubashir
相关产品推荐
相关产品推荐

