Skip to content

好的,我们来探讨一个衡量应用专业度的核心指标:性能 (Performance)。这就像是评估你那家餐厅的运营效率,不仅要菜品美味(功能正确),更要上菜速度快(响应迅速)、能同时服务大量顾客(高吞吐量),并且成本可控(资源消耗低)。

为你的应用注入“涡轮增压”:NestJS 性能优化完全指南

想象你的 NestJS 应用是一家生意兴隆的在线外卖平台。

刚开业时,一天只有几十个订单,你一个厨师(一个 Node.js 进程)就能轻松应对。但随着口碑发酵,订单量暴增到每分钟几百上千个。这时,问题接踵而至:

  • 响应变慢:厨师手忙脚乱,每个订单的处理时间都变长了。
  • 系统过载:厨房(服务器 CPU 和内存)被占满,新订单甚至都挤不进来。
  • 资源浪费:即使在凌晨没什么订单的时候,厨房也开着所有的灯和设备,白白消耗能源。

性能优化,就是通过一系列的技术和策略,让你的平台在高压下依然能保持“高速出餐”和“稳定运营”的能力。NestJS 基于 Node.js,而 Node.js 是单线程的,这意味着它在同一时间只能做一件事。因此,榨干单核性能并有效利用多核 CPU 资源,是性能优化的关键。

1. 基础但关键的优化:“异步大法”

这是 Node.js 性能的基石。任何耗时的操作,特别是 I/O 操作(数据库查询、文件读写、HTTP 请求),都必须是异步的。

错误示范(同步阻塞)❌

typescript
import { readFileSync } from 'fs';

@Injectable()
export class ConfigService {
  constructor() {
    // 使用了同步的 readFileSync
    // 在读取这个文件时,整个 Node.js 进程都会被冻结,无法响应任何其他请求!
    const config = readFileSync('config.json');
  }
}

正确示范(异步非阻塞)✅

typescript
import { promises as fs } from 'fs';

@Injectable()
export class ConfigService implements OnModuleInit {
  private config: any;
  async onModuleInit() {
    // 使用异步的 readFile
    // 在读取文件时,进程可以继续处理其他任务,完成后再回来执行 .then 或 await 后面的代码
    this.config = JSON.parse(await fs.readFile('config.json', 'utf8'));
  }
}
```**核心原则**:永远不要让你的主线程因为等待 I/O 而“发呆”。使用 `async/await` 或 `Promises`,将所有耗时操作都“外包”出去,让主线程持续地接收和处理新任务。

### 2. 榨干单核性能:切换到 Fastify

NestJS 默认使用 Express 作为底层的 HTTP 平台。Express 成熟、稳定、生态庞大。但如果你追求极致的性能,[Fastify](https://www.fastify.io/) 是一个更好的选择。

Fastify 是一个专为性能而生的 Web 框架,它通过高效的路由和 JSON 序列化,能提供比 Express 高出数倍的请求处理速度(QPS, Queries Per Second)。

**如何切换?** 过程简单到令人发指。

**第一步:安装依赖**
```bash
npm uninstall @nestjs/platform-express
npm install @nestjs/platform-fastify

第二步:修改 main.ts

typescript
// main.ts
import { NestFactory } from '@nestjs/core';
import {
  FastifyAdapter,
  NestFastifyApplication,
} from '@nestjs/platform-fastify'; // 导入 Fastify 相关模块
import { AppModule } from './app.module';

async function bootstrap() {
  // 1. 创建一个 Fastify 适配器实例
  const adapter = new FastifyAdapter();

  // 2. 将适配器传入 NestFactory.create(),并指定应用类型
  const app = await NestFactory.create<NestFastifyApplication>(
    AppModule,
    adapter
  );

  await app.listen(3000, '0.0.0.0');
}
bootstrap();

就这样,你的应用底层已经换上了更强劲的“引擎”,而你的 ControllerService 代码一行都不需要改!这就是 NestJS 平台无关性设计的巨大优势。

3. 利用多核 CPU:集群模式 (Clustering)

你的服务器通常都有多个 CPU 核心,但一个 Node.js 进程默认只能使用其中一个,这造成了巨大的资源浪费。集群模式允许你启动多个 Node.js 进程(称为工作进程 Worker),它们共享同一个服务器端口,共同来处理请求。

核心思想

  • 一个主进程 (Master) 负责监听端口和分发请求。
  • N 个工作进程 (Worker)(通常等于 CPU 核心数)负责实际处理请求。

当一个新请求到达时,主进程会像一个“交通警察”,以轮询 (Round-robin) 的方式,将请求分发给一个当前比较空闲的工作进程。这极大地提升了应用的并发处理能力。

NestJS 没有内置的集群方案,但我们可以非常轻松地使用 Node.js 的原生 cluster 模块或更强大的第三方库 pm2 来实现。

方案一:使用 Node.js 原生 cluster 模块

src/cluster.ts```typescript import _ as cluster from 'cluster'; import _ as os from 'os'; import { Injectable, Logger } from '@nestjs/common';

@Injectable() export class ClusterService { private static readonly logger = new Logger(ClusterService.name);

static clusterize(callback: Function): void { const numCPUs = os.cpus().length;

if ((cluster as any).isPrimary) {
  this.logger.log(`Master process ${process.pid} is running`);

  for (let i = 0; i < numCPUs; i++) {
    (cluster as any).fork();
  }

  (cluster as any).on('exit', (worker) => {
    this.logger.error(`Worker ${worker.process.pid} died. Forking a new one...`);
    (cluster as any).fork();
  });
} else {
  this.logger.log(`Worker ${process.pid} started`);
  callback();
}

} }


**`src/main.ts` (修改后)**
```typescript
// ... imports
import { ClusterService } from './cluster';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  // ... 其他配置
  await app.listen(3000);
}

// 使用 ClusterService 来启动
ClusterService.clusterize(bootstrap);

现在,启动应用后,你会看到它根据你的 CPU 核心数启动了多个工作进程。

方案二(企业级推荐):使用 pm2

PM2 是一个用于 Node.js 的、功能极其强大的进程管理器。它不仅能轻松实现集群模式,还提供了日志管理、性能监控、自动重启、滚动更新等一系列生产环境必备的功能。

使用 pm2 是目前中国乃至全球企业部署 Node.js 应用的绝对主流和最佳实践**。**

如何使用?

  1. 全局安装 pm2:

    bash
    npm install pm2 -g
  2. 构建你的 NestJS 应用:

    bash
    npm run build

    这会在 dist 目录下生成编译后的 JavaScript 文件。

  3. 使用 pm2 启动集群:

    bash
    # -i max 表示让 pm2 自动根据 CPU 核心数启动最大数量的实例
    # --name "my-nest-app" 给你的应用起个名字
    pm2 start dist/main.js -i max --name "my-nest-app"

    只需这一行命令! PM2 就会在后台为你处理好所有关于集群、日志、监控和守护的事情。

常用 PM2 命令:

  • pm2 list: 查看所有正在运行的应用。
  • pm2 logs my-nest-app: 查看 my-nest-app 的实时日志。
  • pm2 restart my-nest-app: 重启应用。
  • pm2 stop my-nest-app: 停止应用。

4. 其他重要的性能优化技术(回顾)

除了上述核心技术,我们之前学过的很多内容,其本身就是重要的性能优化手段:

  • 缓存 (@nestjs/cache-manager): 将高频访问的数据或耗时计算的结果放入缓存(如 Redis),避免重复的数据库查询和计算。这是最立竿见影的性能优化手段。
  • 队列 (@nestjs/bull): 将耗时的任务(如发送邮件、视频转码)放入后台队列异步处理,让主 API 接口能立即响应用户。
  • 压缩 (compression): 减小响应体大小,加快网络传输速度。
  • 数据库优化:
    • 索引 (Indexing): 为经常用于查询条件的数据库字段创建索引。这是数据库性能优化的第一要务
    • 连接池 (Connection Pooling): 使用连接池来复用数据库连接,避免频繁地创建和销毁连接。TypeOrmModule 等模块在后台已经为你处理好了。
  • 使用 CDN: 将静态资源(图片、CSS、JS)托管到 CDN (内容分发网络),让用户从离他们最近的节点加载资源。

总结

性能优化是一个系统性的工程,但遵循一些核心原则,就能获得巨大的回报。

优化维度核心技术收益企业级方案
基础编码异步 I/O (async/await)防止主线程阻塞,提升单进程处理能力。始终遵循
单核性能切换到 Fastify数倍的 QPS 提升,降低单次请求的延迟。对于性能敏感的 API 网关或核心服务,非常推荐。
多核利用集群模式充分利用多核 CPU,成倍提升应用总的并发处理能力。强烈推荐使用 PM2,它是生产环境部署的行业标准。
响应速度缓存 (Caching), 队列 (Queues)极大降低响应延迟,提升用户体验,保护数据库。结合 Redis 使用 @nestjs/cache-manager@nestjs/bull
网络传输压缩 (Compression), CDN减少数据传输量,加快客户端加载速度。几乎是所有 Web 应用的标配。

从写好每一行异步代码,到用 PM2 在生产环境部署你的集群,掌握这些性能优化技术,是衡量一个 NestJS 开发者从“能用”到“卓越”的关键分水岭。