乐闻世界logo
搜索文章和话题

NestJS 性能优化有哪些方法?

2月21日 17:11

NestJS 性能优化详解

性能优化概述

性能优化是构建高性能 NestJS 应用程序的关键。通过合理的架构设计、代码优化和资源管理,可以显著提升应用程序的响应速度和吞吐量。

1. 数据库优化

查询优化

使用索引

typescript
@Entity('users') export class User { @PrimaryGeneratedColumn() id: number; @Index() @Column() email: string; @Index() @Column() username: string; @Column() name: string; }

避免 N+1 查询

typescript
// 不好的方式 - N+1 查询 async getUsersWithOrders() { const users = await this.userRepository.find(); for (const user of users) { user.orders = await this.orderRepository.find({ where: { userId: user.id } }); } return users; } // 好的方式 - 使用 JOIN async getUsersWithOrders() { return this.userRepository.find({ relations: ['orders'], }); }

使用分页

typescript
async findAll(page: number = 1, limit: number = 10) { const [data, total] = await this.userRepository.findAndCount({ skip: (page - 1) * limit, take: limit, }); return { data, total, page, totalPages: Math.ceil(total / limit), }; }

连接池配置

typescript
TypeOrmModule.forRoot({ type: 'mysql', host: 'localhost', port: 3306, username: 'root', password: 'password', database: 'test', entities: [User], extra: { connectionLimit: 20, // 根据服务器配置调整 }, })

2. 缓存策略

使用 Redis 缓存

typescript
import { Injectable, Inject } from '@nestjs/common'; import { CACHE_MANAGER } from '@nestjs/cache-manager'; import { Cache } from 'cache-manager'; @Injectable() export class UserService { constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {} async findOne(id: number) { const cacheKey = `user_${id}`; const cachedUser = await this.cacheManager.get(cacheKey); if (cachedUser) { return cachedUser; } const user = await this.userRepository.findOne({ where: { id } }); await this.cacheManager.set(cacheKey, user, 3600); // 缓存 1 小时 return user; } }

HTTP 缓存

typescript
import { Controller, Get, Header } from '@nestjs/common'; @Controller('users') export class UsersController { @Get() @Header('Cache-Control', 'public, max-age=300') // 缓存 5 分钟 findAll() { return this.usersService.findAll(); } }

拦截器缓存

typescript
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common'; import { Observable } from 'rxjs'; import { tap } from 'rxjs/operators'; @Injectable() export class CacheInterceptor implements NestInterceptor { private cache = new Map(); intercept(context: ExecutionContext, next: CallHandler): Observable<any> { const request = context.switchToHttp().getRequest(); const cacheKey = request.url; if (this.cache.has(cacheKey)) { return of(this.cache.get(cacheKey)); } return next.handle().pipe( tap(data => { this.cache.set(cacheKey, data); }), ); } }

3. 异步处理

使用异步/等待

typescript
// 好的方式 async findAll() { return this.userRepository.find(); } // 不好的方式 - 同步阻塞 findAll() { return this.userRepository.findSync(); }

并行处理

typescript
// 不好的方式 - 串行执行 async getUserData(userId: number) { const user = await this.userRepository.findOne({ where: { id: userId } }); const orders = await this.orderRepository.find({ where: { userId } }); const notifications = await this.notificationRepository.find({ where: { userId } }); return { user, orders, notifications }; } // 好的方式 - 并行执行 async getUserData(userId: number) { const [user, orders, notifications] = await Promise.all([ this.userRepository.findOne({ where: { id: userId } }), this.orderRepository.find({ where: { userId } }), this.notificationRepository.find({ where: { userId } }), ]); return { user, orders, notifications }; }

使用队列处理耗时任务

typescript
import { Injectable } from '@nestjs/common'; import { InjectQueue } from '@nestjs/bull'; import { Queue } from 'bull'; @Injectable() export class EmailService { constructor(@InjectQueue('email') private emailQueue: Queue) {} async sendEmail(to: string, subject: string, body: string) { await this.emailQueue.add('send-email', { to, subject, body }); } }

4. 压缩

启用 Gzip 压缩

typescript
import compression from 'compression'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.use(compression()); await app.listen(3000); }

配置压缩级别

typescript
app.use(compression({ level: 6, // 压缩级别 1-9 threshold: 1024, // 只压缩大于 1KB 的响应 }));

5. 静态资源优化

使用 CDN

typescript
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); // 配置静态资源使用 CDN app.useStaticAssets('public', { prefix: '/static/', cacheControl: true, maxAge: 31536000, // 1 年 }); await app.listen(3000); }

图片优化

typescript
import { Controller, Get, Param, Res } from '@nestjs/common'; import { Response } from 'express'; import sharp from 'sharp'; @Controller('images') export class ImageController { @Get(':filename') async getImage(@Param('filename') filename: string, @Res() res: Response) { const image = sharp(`./public/images/${filename}`); // 根据请求参数优化图片 const width = parseInt(req.query.width) || 800; const height = parseInt(req.query.height) || 600; image .resize(width, height) .jpeg({ quality: 80 }) .pipe(res); } }

6. 代码优化

使用懒加载模块

typescript
@Module({ imports: [ // 懒加载模块 UsersModule, OrdersModule, ], }) export class AppModule {}

避免不必要的计算

typescript
// 不好的方式 async processUsers(users: User[]) { return users.map(user => { const expensiveResult = this.expensiveCalculation(user); return { ...user, result: expensiveResult }; }); } // 好的方式 - 使用缓存 async processUsers(users: User[]) { const cache = new Map(); return users.map(user => { const cacheKey = user.id; if (!cache.has(cacheKey)) { cache.set(cacheKey, this.expensiveCalculation(user)); } return { ...user, result: cache.get(cacheKey) }; }); }

使用流处理大数据

typescript
import { Controller, Get, StreamableFile } from '@nestjs/common'; import { createReadStream } from 'fs'; @Controller('files') export class FileController { @Get('download/:filename') downloadFile(@Param('filename') filename: string): StreamableFile { const file = createReadStream(`./files/${filename}`); return new StreamableFile(file); } }

7. 监控和分析

性能监控

typescript
import { Injectable, NestInterceptor, ExecutionContext, CallHandler, Logger } from '@nestjs/common'; import { Observable } from 'rxjs'; import { tap } from 'rxjs/operators'; @Injectable() export class LoggingInterceptor implements NestInterceptor { private readonly logger = new Logger(LoggingInterceptor.name); intercept(context: ExecutionContext, next: CallHandler): Observable<any> { const now = Date.now(); const request = context.switchToHttp().getRequest(); return next.handle().pipe( tap(() => { const duration = Date.now() - now; this.logger.log( `${request.method} ${request.url} - ${duration}ms`, ); }), ); } }

使用 APM 工具

typescript
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { Agent } from '@elastic/apm-node'; const apm = new Agent({ serviceName: 'nestjs-app', serverUrl: 'http://localhost:8200', }); async function bootstrap() { const app = await NestFactory.create(AppModule); await app.listen(3000); } bootstrap();

8. 负载均衡

使用 PM2 集群模式

bash
npm install pm2 -g pm2 start dist/main.js -i max --name nestjs-app

配置 PM2

javascript
// ecosystem.config.js module.exports = { apps: [{ name: 'nestjs-app', script: './dist/main.js', instances: 'max', exec_mode: 'cluster', env: { NODE_ENV: 'production', PORT: 3000, }, }], };

9. 内存优化

避免内存泄漏

typescript
// 不好的方式 - 可能导致内存泄漏 @Injectable() export class CacheService { private cache = new Map(); set(key: string, value: any) { this.cache.set(key, value); } } // 好的方式 - 使用 TTL @Injectable() export class CacheService { private cache = new Map(); private ttl = 3600000; // 1 小时 set(key: string, value: any) { this.cache.set(key, { value, expires: Date.now() + this.ttl, }); // 定期清理过期缓存 this.cleanup(); } private cleanup() { const now = Date.now(); for (const [key, data] of this.cache.entries()) { if (data.expires < now) { this.cache.delete(key); } } } }

使用对象池

typescript
@Injectable() export class ObjectPool<T> { private pool: T[] = []; private factory: () => T; constructor(factory: () => T, size: number = 10) { this.factory = factory; for (let i = 0; i < size; i++) { this.pool.push(factory()); } } acquire(): T { return this.pool.pop() || this.factory(); } release(obj: T): void { this.pool.push(obj); } }

10. 网络优化

使用 HTTP/2

typescript
import { NestFactory } from '@nestjs/core'; import { AppModule } from './app.module'; import { NestExpressApplication } from '@nestjs/platform-express'; async function bootstrap() { const app = await NestFactory.create<NestExpressApplication>(AppModule); await app.listen(3000); } bootstrap();

配置 Keep-Alive

typescript
async function bootstrap() { const app = await NestFactory.create(AppModule); const server = app.getHttpServer(); server.keepAliveTimeout = 65000; server.headersTimeout = 66000; await app.listen(3000); }

性能优化最佳实践

  1. 监控性能:持续监控应用程序性能指标
  2. 基准测试:建立性能基准并定期测试
  3. 渐进优化:逐步优化,每次只优化一个方面
  4. 代码审查:定期进行代码审查以发现性能问题
  5. 使用缓存:合理使用缓存减少数据库查询
  6. 异步处理:使用异步和并行处理提高效率
  7. 资源压缩:启用压缩减少传输数据量
  8. 负载均衡:使用负载均衡分散请求压力
  9. 定期清理:定期清理缓存和临时数据
  10. 文档记录:记录优化过程和结果

总结

NestJS 性能优化提供了:

  • 数据库查询优化
  • 多种缓存策略
  • 异步处理能力
  • 资源压缩技术
  • 监控和分析工具

掌握性能优化是构建高性能 NestJS 应用程序的关键。通过合理应用各种优化技术和最佳实践,可以显著提升应用程序的性能、响应速度和用户体验。性能优化是一个持续的过程,需要根据实际应用场景不断调整和改进。

标签:NestJS