性能与架构
本教程共 47 篇 · 第 47 篇 · 更新于 2026-08-09 · 约 14 分钟阅读
本节目标:掌握NestJS性能优化技巧和架构设计模式,学会用Fastify提升性能、懒加载模块加速启动、缓存和队列优化响应,设计可扩展的应用架构。
教程到了最后一章,我们来聊聊性能和架构。应用跑起来只是第一步,跑得快、扛得住才是真本事。
使用Fastify提升性能
NestJS默认用Express,但Express不是最快的。Fastify比Express快将近一倍,如果性能是首要考虑,换Fastify。
安装
npm install @nestjs/platform-fastify
切换适配器
import { NestFactory } from '@nestjs/core';
import {
FastifyAdapter,
NestFastifyApplication,
} from '@nestjs/platform-fastify';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter()
);
await app.listen(3000, '0.0.0.0');
}
bootstrap();
'0.0.0.0'让Fastify监听所有网络接口,不然默认只监听localhost。
注意事项
换Fastify后,有些Express的中间件不能直接用,要找Fastify的替代品。比如:
cookie-parser换成@fastify/cookieexpress-session换成@fastify/secure-sessionhelmet换成@fastify/helmet
大部分常用中间件都有Fastify版本,迁移成本不算高。
Tip如果项目已经用Express跑得好好的,没必要为了性能换Fastify。Express生态更成熟,中间件更多。新项目或者性能瓶颈明显时再考虑。
懒加载模块
默认情况下,所有模块在应用启动时就会加载。模块多了,启动时间就长。在Serverless环境里,启动慢意味着”冷启动”时间长,用户体验差。
懒加载让你按需加载模块,只在用到的时候才加载。
使用LazyModuleLoader
import { Injectable } from '@nestjs/common';
import { LazyModuleLoader } from '@nestjs/core';
@Injectable()
export class CatsService {
constructor(private lazyModuleLoader: LazyModuleLoader) {}
async doSomething() {
// 动态导入模块
const { LazyModule } = await import('./lazy.module');
const moduleRef = await this.lazyModuleLoader.load(() => LazyModule);
// 获取模块里的服务
const { LazyService } = await import('./lazy.service');
const lazyService = moduleRef.get(LazyService);
return lazyService.doWork();
}
}
第一次加载模块会慢一些,之后会走缓存,速度很快:
Load "LazyModule" attempt: 1
time: 2.379ms
Load "LazyModule" attempt: 2
time: 0.294ms
Load "LazyModule" attempt: 3
time: 0.303ms
适用场景
懒加载适合这些场景:
- Serverless函数:根据请求参数加载不同的模块
- 定时任务:不同的cron job加载不同的处理模块
- Webhook:根据事件类型加载不同的处理器
Warning懒加载模块里的控制器、网关、GraphQL解析器不会正常工作。因为路由注册必须在应用启动前完成。懒加载只适合纯服务类模块。
缓存策略
频繁查询数据库是性能杀手。把结果缓存起来,下次直接返回。
内存缓存
用cache-manager实现简单的内存缓存:
npm install cache-manager
npm install @types/cache-manager
import { CacheModule, CacheInterceptor } from '@nestjs/common';
import { Controller, Get, UseInterceptors } from '@nestjs/common';
@Module({
imports: [
CacheModule.register({
ttl: 60, // 缓存60秒
max: 100, // 最多缓存100条
}),
],
})
export class AppModule {}
@Controller('cats')
export class CatsController {
@Get()
@UseInterceptors(CacheInterceptor)
findAll() {
// 第一次请求会执行,之后60秒内直接返回缓存
return this.catsService.findAll();
}
}
CacheInterceptor自动缓存GET请求的响应。
手动控制缓存
有时候需要更精细的控制:
import { CACHE_MANAGER } from '@nestjs/common';
import { Cache } from 'cache-manager';
import { Inject } from '@nestjs/common';
@Injectable()
export class CatsService {
constructor(@Inject(CACHE_MANAGER) private cache: Cache) {}
async findAll(): Promise<Cat[]> {
const cacheKey = 'cats_all';
const cats = await this.cache.get(cacheKey);
if (cats) {
return cats;
}
const result = await this.db.cats.find();
await this.cache.set(cacheKey, result, 60);
return result;
}
async create(cat: CreateCatDto) {
const result = await this.db.cats.create(cat);
// 创建后清除缓存
await this.cache.del('cats_all');
return result;
}
}
Redis缓存
生产环境用Redis做缓存,支持分布式共享:
import { redisStore } from 'cache-manager-redis-store';
CacheModule.register({
store: await redisStore({
host: 'localhost',
port: 6379,
}),
ttl: 60,
})
队列处理
有些操作很耗时,比如发邮件、生成报表。同步处理会让用户等很久。把这些任务扔进队列,后台慢慢处理。
使用Bull队列
npm install @nestjs/bull bull
npm install -D @types/bull
import { BullModule } from '@nestjs/bull';
@Module({
imports: [
BullModule.forRoot({
redis: {
host: 'localhost',
port: 6379,
},
}),
BullModule.registerQueue({
name: 'email',
}),
],
})
export class AppModule {}
生产者:添加任务到队列
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 sendWelcomeEmail(userId: string) {
await this.emailQueue.add('welcome', { userId });
// 立即返回,不等邮件发完
}
}
消费者:处理队列任务
import { Processor, Process } from '@nestjs/bull';
import { Job } from 'bull';
@Processor('email')
export class EmailProcessor {
@Process('welcome')
async handleWelcomeEmail(job: Job) {
const { userId } = job.data;
// 发送邮件的逻辑
console.log(`Sending welcome email to user ${userId}`);
}
}
队列的好处:
- 异步处理:用户不用等
- 失败重试:失败了自动重试
- 限流:控制并发数,不会压垮第三方服务
- 削峰填谷:高峰期排队的任务,低峰期慢慢处理
数据库优化
数据库往往是性能瓶颈。几个优化方向:
索引优化
给常用查询字段加索引:
@Entity()
export class User {
@Index() // 加索引
@Column()
email: string;
@Index()
@Column()
createdAt: Date;
}
分页查询
别一次查所有数据,用分页:
async findAll(page: number, limit: number) {
return this.userRepository.find({
skip: (page - 1) * limit,
take: limit,
});
}
连接池
数据库连接是宝贵的,用连接池复用:
TypeOrmModule.forRoot({
type: 'postgres',
host: 'localhost',
port: 5432,
// 连接池配置
extra: {
max: 20, // 最大连接数
min: 5, // 最小连接数
idleTimeoutMillis: 30000,
},
})
避免N+1查询
用TypeORM的relations选项预加载关联数据:
// 不好:N+1查询
const users = await this.userRepository.find();
for (const user of users) {
user.posts = await this.postRepository.find({
where: { userId: user.id }
});
}
// 好:一次查询
const users = await this.userRepository.find({
relations: ['posts'],
});
架构模式
分层架构
NestJS天然支持分层架构:
Controller → Service → Repository → Database
↓ ↓
Guard Interceptor
↓ ↓
Pipe Filter
每层各司其职:
- Controller:接收请求,返回响应
- Service:业务逻辑
- Repository:数据访问
- Guard:权限控制
- Interceptor:请求/响应拦截
- Pipe:数据验证和转换
- Filter:异常处理
模块化设计
按业务领域划分模块,而不是按技术层:
src/
├── users/ # 用户模块
│ ├── users.module.ts
│ ├── users.controller.ts
│ ├── users.service.ts
│ └── users.repository.ts
├── orders/ # 订单模块
│ ├── orders.module.ts
│ ├── orders.controller.ts
│ ├── orders.service.ts
│ └── orders.repository.ts
├── payments/ # 支付模块
│ └── ...
└── shared/ # 共享模块
├── auth/
├── cache/
└── logger/
依赖倒置
高层模块不依赖低层模块,都依赖抽象:
// 定义接口
export interface IUserRepository {
findById(id: number): Promise<User>;
save(user: User): Promise<User>;
}
// 实现接口
@Injectable()
export class TypeOrmUserRepository implements IUserRepository {
constructor(
@InjectRepository(User)
private repo: Repository<User>
) {}
async findById(id: number) {
return this.repo.findOne({ where: { id } });
}
async save(user: User) {
return this.repo.save(user);
}
}
// 服务依赖接口,不依赖具体实现
@Injectable()
export class UsersService {
constructor(
@Inject('IUserRepository')
private userRepo: IUserRepository
) {}
}
好处是随时能换实现,测试时也好Mock。
事件驱动
用事件解耦模块间的依赖:
// 定义事件
export class UserCreatedEvent {
constructor(public readonly userId: string) {}
}
// 发布事件
@Injectable()
export class UsersService {
constructor(private eventEmitter: EventEmitter2) {}
async create(dto: CreateUserDto) {
const user = await this.repo.save(dto);
this.eventEmitter.emit('user.created', new UserCreatedEvent(user.id));
return user;
}
}
// 监听事件
@Injectable()
export class EmailListener {
@OnEvent('user.created')
handleUserCreated(event: UserCreatedEvent) {
// 发送欢迎邮件
}
}
用户服务不需要知道谁在监听,邮件服务不需要知道用户是怎么创建的。松耦合,好维护。
性能监控
优化之前先测量,不然不知道优化了啥。
请求耗时
用拦截器记录每个请求的耗时:
import {
Injectable,
NestInterceptor,
ExecutionContext,
CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
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;
console.log(`${request.method} ${request.url} - ${duration}ms`);
}),
);
}
}
内存使用
监控内存使用,防止内存泄漏:
setInterval(() => {
const usage = process.memoryUsage();
console.log({
rss: `${Math.round(usage.rss / 1024 / 1024)}MB`,
heap: `${Math.round(usage.heapUsed / 1024 / 1024)}MB`,
});
}, 60000);
APM工具
生产环境用APM工具(如New Relic、Datadog、SkyWalking)监控:
- 请求响应时间
- 错误率
- 数据库查询耗时
- 外部服务调用耗时
架构演进
单体应用
刚开始用单体应用,所有模块在一个进程里。简单、好部署、好调试。
垂直拆分
流量大了,把耗资源的模块拆出来单独部署:
┌─────────────┐ ┌─────────────┐
│ API Gateway │────▶│ User Service│
└──────┬──────┘ └─────────────┘
│
│ ┌─────────────┐
└───────────▶│ Order Service│
└─────────────┘
微服务
继续拆分,每个业务领域一个微服务。NestJS的微服务支持让你平滑过渡。
Tip别一上来就搞微服务。单体应用能扛住就别拆。微服务的复杂度远超单体,运维成本也高。等业务真的需要了再拆。
小结
这一章学了NestJS性能优化和架构设计:
Fastify:比Express快一倍,适合性能敏感的场景。
懒加载:按需加载模块,加速Serverless冷启动。
缓存:用cache-manager缓存频繁查询的数据,Redis支持分布式共享。
队列:用Bull处理耗时任务,异步、重试、限流。
数据库优化:索引、分页、连接池、避免N+1查询。
架构模式:分层架构、模块化设计、依赖倒置、事件驱动。
性能监控:拦截器记录耗时,APM工具全面监控。
架构演进:单体 → 垂直拆分 → 微服务,按需演进。
性能优化不是一蹴而就的。先跑起来,再跑快。找到瓶颈,针对性优化。架构设计也不是一步到位的。先简单,再复杂。业务发展到哪一步,架构就演进到哪一步。
恭喜你完成了整个NestJS教程!从基础概念到高级技巧,从测试到部署,从性能到架构,你已经掌握了NestJS开发的核心知识。接下来就是动手实践,在真实项目中磨练技能。加油!