第二十课:生产部署与架构设计

3 阅读12分钟

覆盖文档:Deployment, Performance(Fastify), Health Checks, Serverless, HTTPS, Keep-Alive, Common Errors, DevTools, CQRS, Async Local Storage, Nest Commander, SWC, Sentry 前置知识:全部前序课程 源码重点:packages/platform-fastify/adapters/fastify-adapter.ts, packages/core/nest-application.ts


一、构建与部署基础

[基础] 本节面向初学者,掌握 NestJS 应用的构建、容器化与健康检查。

1.1 构建与运行

# 1. 编译 TypeScript → JavaScript
npm run build
# 输出到 dist/ 目录

# 2. 以生产模式运行
NODE_ENV=production node dist/main.js

构建产物结构:

dist/
├── main.js                 # 应用入口
├── app.module.js           # 根模块
├── app.controller.js       # 控制器
├── app.service.js          # 服务
└── ...                     # 其他编译后的文件

1.2 Docker 多阶段构建

多阶段构建将编译环境与运行环境分离,大幅减小镜像体积:

# ============ 阶段一:构建 ============
FROM node:20-alpine AS builder

WORKDIR /app

# 1. 先复制依赖文件(利用 Docker 层缓存)
COPY package*.json ./
RUN npm ci --only=production && \
    cp -R node_modules prod_node_modules && \
    npm ci

# 2. 复制源码并编译
COPY . .
RUN npm run build

# ============ 阶段二:运行 ============
FROM node:20-alpine AS runner

WORKDIR /app

# 3. 只复制运行所需文件
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/prod_node_modules ./node_modules

# 4. 安全:使用非 root 用户
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nestjs -u 1001
USER nestjs

EXPOSE 3000

# 5. 设置生产环境变量
ENV NODE_ENV=production

# 6. 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1

CMD ["node", "dist/main.js"]

.dockerignore 文件:

node_modules
dist
.git
.github
*.md
.env*
test
coverage

1.3 健康检查 — @nestjs/terminus

健康检查是生产部署的必备组件,让负载均衡器和编排系统知道应用是否正常运行:

npm install --save @nestjs/terminus
// health/health.module.ts
import { Module } from '@nestjs/common';
import { TerminusModule } from '@nestjs/terminus';
import { HealthController } from './health.controller';

@Module({
  imports: [TerminusModule],
  controllers: [HealthController],
})
export class HealthModule {}
// health/health.controller.ts
import { Controller, Get } from '@nestjs/common';
import {
  HealthCheckService,
  HealthCheck,
  HttpHealthIndicator,
  TypeOrmHealthIndicator,
  DiskHealthIndicator,
  MemoryHealthIndicator,
} from '@nestjs/terminus';

@Controller('health')
export class HealthController {
  constructor(
    private readonly health: HealthCheckService,
    private readonly http: HttpHealthIndicator,
    private readonly db: TypeOrmHealthIndicator,
    private readonly disk: DiskHealthIndicator,
    private readonly memory: MemoryHealthIndicator,
  ) {}

  @Get()
  @HealthCheck()
  check() {
    return this.health.check([
      // HTTP 外部依赖检查
      () => this.http.pingCheck('api-docs', 'https://docs.nestjs.com'),

      // 数据库连接检查
      () => this.db.pingCheck('database'),

      // 磁盘空间检查(阈值 90%)
      () => this.disk.checkStorage('disk', {
        path: '/',
        thresholdPercent: 0.9,
      }),

      // 内存检查(阈值 300MB)
      () => this.memory.checkHeap('memory_heap', 300 * 1024 * 1024),

      // RSS 内存检查(阈值 500MB)
      () => this.memory.checkRSS('memory_rss', 500 * 1024 * 1024),
    ]);
  }
}

自定义健康指标:

import { Injectable } from '@nestjs/common';
import { HealthIndicatorService, HealthIndicatorResult } from '@nestjs/terminus';

@Injectable()
export class RedisHealthIndicator {
  constructor(
    private readonly healthIndicatorService: HealthIndicatorService,
    private readonly redisService: RedisService,
  ) {}

  async isHealthy(key: string): Promise<HealthIndicatorResult> {
    const indicator = this.healthIndicatorService.check(key);
    try {
      await this.redisService.ping();
      return indicator.up();
    } catch (error) {
      return indicator.down({ message: error.message });
    }
  }
}

内置健康指标速查:

指标检查内容
HTTPHttpHealthIndicator外部 HTTP 服务可达性
TypeORMTypeOrmHealthIndicator数据库连接状态
MongooseMongooseHealthIndicatorMongoDB 连接状态
MikroORMMikroOrmHealthIndicatorMikroORM 连接状态
PrismaPrismaHealthIndicatorPrisma 连接状态
磁盘DiskHealthIndicator磁盘空间使用率
内存MemoryHealthIndicator堆内存 / RSS 使用量

二、生产最佳实践

[中阶] 本节面向有经验的开发者,掌握生产环境配置要点。

2.1 环境变量与配置

生产环境绝不硬编码配置,使用 ConfigService 管理:

// main.ts
import { ConfigService } from '@nestjs/config';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  const configService = app.get(ConfigService);

  const port = configService.get<number>('PORT', 3000);
  const host = configService.get<string>('HOST', '0.0.0.0');

  await app.listen(port, host);
}

2.2 JSON 日志与 Correlation ID

生产环境使用结构化 JSON 日志,便于 ELK/Datadog 等系统收集和分析:

import { NestFactory } from '@nestjs/core';
import { ConsoleLogger } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule, {
    // JSON 格式日志输出
    logger: new ConsoleLogger({
      json: true,
      colors: false,          // 生产环境不需要颜色
    }),
  });

  await app.listen(3000);
}

Correlation ID 中间件贯穿请求全链路:

import { Injectable, NestMiddleware } from '@nestjs/common';
import { randomUUID } from 'crypto';

@Injectable()
export class CorrelationIdMiddleware implements NestMiddleware {
  use(req: any, res: any, next: () => void) {
    const correlationId = req.headers['x-correlation-id'] || randomUUID();
    req.correlationId = correlationId;
    res.setHeader('x-correlation-id', correlationId);
    next();
  }
}

2.3 优雅关闭

async function bootstrap() {
  const app = await NestFactory.create(AppModule, {
    // 优雅关闭时不等待 Keep-Alive 连接超时
    forceCloseConnections: true,
  });

  // 启用关闭钩子(监听 SIGTERM、SIGINT)
  app.enableShutdownHooks();

  await app.listen(3000);
}

2.4 HTTPS 配置

import { readFileSync } from 'fs';

async function bootstrap() {
  const httpsOptions = {
    key: readFileSync('./secrets/private-key.pem'),
    cert: readFileSync('./secrets/certificate.pem'),
  };

  const app = await NestFactory.create(AppModule, { httpsOptions });
  await app.listen(443);
}

同时运行 HTTP 重定向 + HTTPS 服务器:

import { NestFactory } from '@nestjs/core';
import * as express from 'express';
import * as http from 'http';

async function bootstrap() {
  // 1. 创建 HTTPS 应用
  const app = await NestFactory.create(AppModule, { httpsOptions });
  await app.listen(443);

  // 2. 创建 HTTP 重定向服务器
  const httpApp = express();
  httpApp.get('*', (req, res) => {
    res.redirect(301, `https://${req.headers.host}${req.url}`);
  });
  http.createServer(httpApp).listen(80);
}

2.5 全局前缀与排除

app.setGlobalPrefix('api', {
  exclude: [
    'health',                                // 健康检查不加前缀
    { path: 'metrics', method: RequestMethod.GET },  // 指标端点
  ],
});
// 结果:GET /api/cats, GET /api/users, GET /health, GET /metrics

2.6 Raw Body — Webhook 签名验证

const app = await NestFactory.create(AppModule, {
  rawBody: true,          // 启用原始请求体
});

// 在 Controller 中获取原始 body
@Post('webhook')
handleWebhook(@RawBody() rawBody: Buffer, @Headers('x-signature') signature: string) {
  // 使用 rawBody 验证签名
  const isValid = verifySignature(rawBody, signature);
  if (!isValid) {
    throw new UnauthorizedException('Invalid webhook signature');
  }
}

2.7 SWC 加速编译 + Fastify 提升吞吐

# SWC 编译(约 20 倍于 tsc)
npm install --save-dev @swc/cli @swc/core
nest start -b swc --watch

# Fastify 平台(约 2 倍于 Express 吞吐)
npm install --save @nestjs/platform-fastify
import { FastifyAdapter, NestFastifyApplication } from '@nestjs/platform-fastify';

const app = await NestFactory.create<NestFastifyApplication>(
  AppModule,
  new FastifyAdapter(),
);
await app.listen(3000, '0.0.0.0');
优化手段效果适用阶段
SWC~20x 编译加速开发 + 构建
Fastify~2x 吞吐提升运行时
forceCloseConnections快速关闭部署重启

2.8 Sentry 错误追踪

npm install --save @sentry/nestjs @sentry/profiling-node
// instrument.ts — 必须在应用启动前加载
import * as Sentry from '@sentry/nestjs';

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  environment: process.env.NODE_ENV,
  tracesSampleRate: 1.0,
});
// app.module.ts
import { SentryModule } from '@sentry/nestjs/setup';

@Module({
  imports: [
    SentryModule.forRoot(),         // 注册 Sentry 模块
    // ... 其他模块
  ],
})
export class AppModule {}
// main.ts
import { SentryGlobalFilter } from '@sentry/nestjs/setup';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // 全局异常过滤器 — 自动上报未捕获异常到 Sentry
  const { httpAdapter } = app.get(HttpAdapterHost);
  app.useGlobalFilters(new SentryGlobalFilter(httpAdapter));

  await app.listen(3000);
}

三、扩展与运维

[中阶] 本节面向有经验的开发者,掌握应用的扩展策略。

3.1 扩展策略

┌─────────────────────────────────────────────────────┐
│                    扩展方式                           │
│                                                     │
│  垂直扩展(Scale Up)          水平扩展(Scale Out)    │
│  ┌──────────┐                ┌──────────────────┐   │
│  │  更多 CPU  │               │  实例1  实例2  实例3 │  │
│  │  更多 RAM  │               │    ↑      ↑      ↑  │  │
│  │  更快磁盘  │               │    └──────┼──────┘  │  │
│  │  单台服务器 │               │     负载均衡器       │  │
│  └──────────┘                └──────────────────┘   │
│                                                     │
│  适用:快速解决,小规模         适用:大规模,高可用    │
│  限制:单机上限               注意:无状态设计         │
└─────────────────────────────────────────────────────┘

水平扩展的前提:应用必须无状态

  • Session 存储在 Redis,不存在内存
  • 文件上传到对象存储(S3/OSS),不存在本地
  • 缓存使用 Redis,不使用进程内存
  • WebSocket 使用 Redis Adapter 同步

3.2 Docker Compose 编排

# docker-compose.yml
version: '3.8'

services:
  api:
    build: .
    ports:
      - '3000:3000'
    environment:
      - NODE_ENV=production
      - DATABASE_HOST=postgres
      - REDIS_HOST=redis
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    restart: unless-stopped
    healthcheck:
      test: ['CMD', 'wget', '--spider', '-q', 'http://localhost:3000/health']
      interval: 30s
      timeout: 5s
      retries: 3

  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: nestapp
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASS}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U ${DB_USER}']
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    volumes:
      - redis_data:/data
    healthcheck:
      test: ['CMD', 'redis-cli', 'ping']
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  postgres_data:
  redis_data:

3.3 CI/CD 流水线

┌─────────┐    ┌─────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐
│  Git     │ →  │  Lint   │ →  │   Test   │ →  │  Build   │ →  │  Deploy  │
│  Push    │    │  + Type │    │  + Cover │    │  Docker  │    │  K8s /   │
│          │    │  Check  │    │  80%+    │    │  Image   │    │  ECS     │
└─────────┘    └─────────┘    └──────────┘    └──────────┘    └──────────┘
                                  ↓ fail
                              阻止合并

关键步骤:

  1. Lint + 类型检查eslint + tsc --noEmit
  2. 测试 + 覆盖率jest --coverage,阈值 80%
  3. 构建 Docker 镜像:多阶段构建
  4. 推送镜像:到私有仓库
  5. 部署:滚动更新(zero-downtime)

四、Serverless 与特殊场景

[高阶] 本节面向深入使用者,掌握 Serverless 部署、CLI 应用和常见错误排查。

4.1 AWS Lambda — Serverless 部署

npm install --save @codegenie/serverless-express
// lambda.ts
import { NestFactory } from '@nestjs/core';
import { ExpressAdapter } from '@nestjs/platform-express';
import serverlessExpress from '@codegenie/serverless-express';
import { Callback, Context, Handler } from 'aws-lambda';
import * as express from 'express';
import { AppModule } from './app.module';

let server: Handler;

async function bootstrap(): Promise<Handler> {
  const expressApp = express();
  const nestApp = await NestFactory.create(
    AppModule,
    new ExpressAdapter(expressApp),
  );
  await nestApp.init();
  return serverlessExpress({ app: expressApp });
}

export const handler: Handler = async (
  event: any,
  context: Context,
  callback: Callback,
) => {
  // 复用实例,减少冷启动
  server = server ?? (await bootstrap());
  return server(event, context, callback);
};

冷启动优化 — LazyModuleLoader:

import { LazyModuleLoader } from '@nestjs/core';

@Injectable()
export class AppService {
  constructor(private readonly lazyModuleLoader: LazyModuleLoader) {}

  async processReport() {
    // 按需加载重量级模块,减少冷启动时间
    const { ReportModule } = await import('./report/report.module');
    const moduleRef = await this.lazyModuleLoader.load(() => ReportModule);
    const reportService = moduleRef.get(ReportService);
    return reportService.generate();
  }
}

4.2 Nest Commander — CLI 应用

npm install nest-commander
import { Command, CommandRunner, Option } from 'nest-commander';

@Command({
  name: 'seed',
  description: '初始化数据库种子数据',
})
export class SeedCommand extends CommandRunner {
  constructor(private readonly seedService: SeedService) {
    super();
  }

  async run(passedParams: string[], options?: Record<string, any>): Promise<void> {
    const count = options?.count ?? 10;
    console.log(`Seeding ${count} records...`);
    await this.seedService.seed(count);
    console.log('Seeding complete!');
  }

  @Option({
    flags: '-c, --count <count>',
    description: '生成的记录数量',
  })
  parseCount(val: string): number {
    return parseInt(val, 10);
  }
}
// main.ts(CLI 模式)
import { CommandFactory } from 'nest-commander';
import { AppModule } from './app.module';

async function bootstrap() {
  await CommandFactory.run(AppModule, ['warn', 'error']);
}
bootstrap();
# 运行 CLI 命令
npx ts-node src/main.ts seed --count 100

4.3 AsyncLocalStorage — nestjs-cls

替代 Request-scoped Provider,无 Scope 冒泡开销:

npm install nestjs-cls
import { ClsModule, ClsService } from 'nestjs-cls';

@Module({
  imports: [
    ClsModule.forRoot({
      global: true,
      middleware: {
        mount: true,
        setup: (cls, req) => {
          // 在请求开始时设置值
          cls.set('userId', req.headers['x-user-id']);
          cls.set('correlationId', req.headers['x-correlation-id'] || randomUUID());
        },
      },
    }),
  ],
})
export class AppModule {}
// 在任何 Service 中获取请求上下文(无需 Scope.REQUEST)
@Injectable()
export class AuditService {
  constructor(private readonly cls: ClsService) {}

  log(action: string) {
    const userId = this.cls.get('userId');
    const correlationId = this.cls.get('correlationId');
    console.log(`[${correlationId}] User ${userId}: ${action}`);
  }
}
方案Scope 冒泡性能影响使用场景
Scope.REQUEST有(整条依赖链)简单场景
nestjs-cls极低推荐方案

4.4 REPL 模式

运行时交互式探索 DI 容器,用于调试和快速验证:

// repl.ts
import { repl } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const replServer = await repl(AppModule);
  replServer.setupHistory('.nestjs_repl_history', (err) => {
    if (err) console.error(err);
  });
}
bootstrap();
npm run start -- --entryFile repl

4.5 常见错误排查

"Cannot resolve dependency" 错误

Nest can't resolve dependencies of the CatsService (?).
Please make sure that the argument "CatsRepository" at index [0]
is available in the CatsModule context.

排查步骤:

// 1. 确认 Provider 在 providers 数组中
@Module({
  providers: [CatsService, CatsRepository],   // CatsRepository 不能遗漏
})

// 2. 如果依赖来自其他模块,确认已 import 且已 export
@Module({
  imports: [DatabaseModule],                   // 需要 import
})

// 3. 循环依赖使用 forwardRef
@Injectable()
export class CatsService {
  constructor(
    @Inject(forwardRef(() => DogsService))     // 解决循环依赖
    private readonly dogsService: DogsService,
  ) {}
}

// 4. 启用调试模式查看详细信息
// 设置环境变量
// NEST_DEBUG=true

避免 Barrel File 导致的虚假循环依赖

// 错误:从 barrel file 导入可能导致循环依赖
import { CatsService } from './';            // index.ts 重导出

// 正确:直接从文件导入
import { CatsService } from './cats.service';

五、性能调优与 DevTools

[资深] 本节面向希望深入理解框架内部机制的读者。

5.1 SWC vs tsc 对比

特性tscSWC
语言TypeScript(自举)Rust
编译速度基准~20x 更快
类型检查内置不支持(需额外 --type-check
装饰器元数据原生支持支持(@swc/core v1.3+)
Swagger Plugin支持不支持
Watch 模式支持支持
// nest-cli.json — SWC 配置
{
  "compilerOptions": {
    "builder": "swc",
    "typeCheck": true       // 并行运行类型检查
  }
}

5.2 Fastify 适配器源码

文件位置:packages/platform-fastify/adapters/fastify-adapter.ts

export class FastifyAdapter extends AbstractHttpAdapter {
  // Fastify 实例
  private readonly instance: FastifyInstance;

  constructor(instanceOrOptions?: FastifyInstance | FastifyServerOptions) {
    const instance = instanceOrOptions instanceof Object && 'server' in instanceOrOptions
      ? instanceOrOptions as FastifyInstance
      : fastify(instanceOrOptions as FastifyServerOptions);

    super(instance);
  }

  // 路由注册 — 映射 NestJS 装饰器到 Fastify 路由
  public get(handler: RequestHandler);
  public get(path: string, handler: RequestHandler);
  public get(...args: any[]) {
    return this.injectConstraintsIfVersioned('GET', ...args);
  }

  // 监听端口 — Fastify 默认只监听 localhost
  public listen(port: number | string, hostname?: string): Promise<void> {
    return this.instance.listen({
      port: typeof port === 'string' ? parseInt(port, 10) : port,
      host: hostname || '0.0.0.0',
    });
  }
}

核心设计:FastifyAdapter 继承 AbstractHttpAdapter,将 NestJS 的路由注册 API 映射到 Fastify 的路由系统。所有平台差异被封装在 Adapter 中,框架核心代码完全平台无关。

5.3 请求管线性能

请求到达 → Middleware → Guard → Interceptor(前) → Pipe → Handler → Interceptor(后) → Filter → 响应
                                                                                    (异常时)

每一层都有开销:
  Middleware:   ~0.01ms(Express/Fastify 原生)
  Guard:        ~0.05ms(含 Reflector 元数据读取)
  Interceptor:  ~0.05ms(RxJS Observable 创建)
  Pipe:         ~0.1-1ms(class-validator 验证最耗时)
  Handler:      业务逻辑时间

优化建议:
  1. 减少全局 Guard/Interceptor 数量
  2. Pipe 验证使用白名单模式(whitelist: true)
  3. 避免不必要的 class-transformer 序列化
  4. 使用 Fastify 替代 Express(底层更快)

5.4 NestJS DevTools

NestJS DevTools 是官方提供的可视化调试工具:

npm install --save @nestjs/devtools-integration
import { DevtoolsModule } from '@nestjs/devtools-integration';

@Module({
  imports: [
    DevtoolsModule.register({
      http: process.env.NODE_ENV !== 'production',
    }),
  ],
})
export class AppModule {}

DevTools 提供的能力:

功能说明
依赖图可视化模块、Provider、Controller 的依赖关系
路由导航查看所有注册路由及其元数据
Playground交互式调用 Provider 方法
性能分析请求管线各阶段耗时
CI/CD 集成在 CI 中生成依赖图快照,检测回归

六、系统架构设计

[架构] 本节面向技术负责人和架构师。

6.1 单体到微服务的演进路径

┌─────────────────────────────────────────────────────────────────┐
│  阶段 1:NestJS 单体应用(模块化设计)                             │
│                                                                 │
│  ┌──────────────────────────────────────────┐                   │
│  │              NestJS 单体                   │                  │
│  │  ┌────────┐ ┌────────┐ ┌────────────┐    │                  │
│  │  │UsersModule│ │OrdersModule│ │PaymentModule│   │                  │
│  │  └────────┘ └────────┘ └────────────┘    │                  │
│  │              共享数据库                     │                  │
│  └──────────────────────────────────────────┘                   │
│  适用:初创期,团队 < 5 人                                        │
│                                                                 │
│                         ↓ 流量增长,团队扩大                      │
│                                                                 │
│  阶段 2:NestJS 混合应用(HTTP + 内部微服务)                       │
│                                                                 │
│  ┌────────────────┐      ┌──────────────────┐                   │
│  │  NestJS HTTP    │ TCP  │  NestJS 微服务     │                  │
│  │  API Gateway    │ ───→ │  PaymentService   │                  │
│  │  (Users+Orders) │      │  (独立数据库)       │                  │
│  └────────────────┘      └──────────────────┘                   │
│  适用:渐进拆分,最小改动成本                                      │
│                                                                 │
│                         ↓ 独立部署需求                            │
│                                                                 │
│  阶段 3:NestJS 微服务集群                                       │
│                                                                 │
│  ┌────────┐  ┌────────┐  ┌────────────┐                        │
│  │ Users   │  │ Orders  │  │  Payment   │                       │
│  │ Service │  │ Service │  │  Service   │                       │
│  └───┬────┘  └───┬────┘  └─────┬──────┘                        │
│      └───────────┼─────────────┘                                │
│           消息总线(NATS / RabbitMQ / Kafka)                      │
│  适用:中大型团队,独立部署和扩展                                   │
│                                                                 │
│                         ↓ 前端查询复杂度增加                      │
│                                                                 │
│  阶段 4:API Gateway + GraphQL Federation + 微服务                │
│                                                                 │
│  ┌──────────────────────────────────┐                           │
│  │        GraphQL Gateway            │                          │
│  │    (Apollo Federation Router)     │                          │
│  └───┬──────────┬──────────┬────────┘                          │
│      │          │          │                                    │
│  ┌───┴───┐  ┌──┴────┐  ┌─┴───────┐                            │
│  │Users  │  │Orders │  │Payment │                              │
│  │Subgraph│  │Subgraph│  │Subgraph│                             │
│  └───────┘  └───────┘  └────────┘                              │
│  适用:大型系统,前端灵活查询需求                                  │
└─────────────────────────────────────────────────────────────────┘

6.2 CQRS 架构

@nestjs/cqrs 实现命令查询职责分离:

npm install --save @nestjs/cqrs
┌─────────────────────────────────────────────────────────────┐
│                       CQRS 架构                              │
│                                                             │
│  写操作(Command)                 读操作(Query)              │
│  ┌────────────────────┐          ┌─────────────────────┐    │
│  │  CreateCatCommand   │          │  GetCatsQuery        │    │
│  │       ↓             │          │       ↓              │    │
│  │  CommandBus         │          │  QueryBus            │    │
│  │       ↓             │          │       ↓              │    │
│  │  CreateCatHandler   │          │  GetCatsHandler      │    │
│  │       ↓             │          │       ↓              │    │
│  │  写入数据库          │          │  读取数据库(可读副本) │    │
│  │       ↓             │          └─────────────────────┘    │
│  │  EventBus           │                                     │
│  │       ↓             │                                     │
│  │  CatCreatedEvent    │                                     │
│  │       ↓             │                                     │
│  │  EventHandler(s)    │                                     │
│  │  (发邮件/更新缓存)   │                                     │
│  └────────────────────┘                                     │
└─────────────────────────────────────────────────────────────┘

实现示例:

// 1. 定义 Command
export class CreateCatCommand {
  constructor(
    public readonly name: string,
    public readonly age: number,
    public readonly breed: string,
  ) {}
}

// 2. 定义 Command Handler
@CommandHandler(CreateCatCommand)
export class CreateCatHandler implements ICommandHandler<CreateCatCommand> {
  constructor(
    private readonly repository: CatsRepository,
    private readonly eventBus: EventBus,
  ) {}

  async execute(command: CreateCatCommand) {
    const cat = await this.repository.create(command);

    // 发布领域事件
    this.eventBus.publish(new CatCreatedEvent(cat.id, cat.name));

    return cat;
  }
}

// 3. 定义 Event
export class CatCreatedEvent {
  constructor(
    public readonly catId: number,
    public readonly catName: string,
  ) {}
}

// 4. 定义 Event Handler
@EventsHandler(CatCreatedEvent)
export class CatCreatedHandler implements IEventHandler<CatCreatedEvent> {
  handle(event: CatCreatedEvent) {
    console.log(`Cat created: ${event.catName}`);
    // 发送通知、更新缓存、同步搜索引擎等
  }
}

// 5. 定义 Query
export class GetCatsQuery {
  constructor(public readonly page: number, public readonly limit: number) {}
}

// 6. 定义 Query Handler
@QueryHandler(GetCatsQuery)
export class GetCatsHandler implements IQueryHandler<GetCatsQuery> {
  constructor(private readonly repository: CatsRepository) {}

  async execute(query: GetCatsQuery) {
    return this.repository.findAll(query.page, query.limit);
  }
}

// 7. Saga — 事件驱动的命令链
@Injectable()
export class CatsSaga {
  @Saga()
  catCreated = (events$: Observable<any>): Observable<ICommand> => {
    return events$.pipe(
      ofType(CatCreatedEvent),
      map((event) => new SendWelcomeEmailCommand(event.catId)),
    );
  };
}
// 8. 在 Controller 中使用
@Controller('cats')
export class CatsController {
  constructor(
    private readonly commandBus: CommandBus,
    private readonly queryBus: QueryBus,
  ) {}

  @Post()
  create(@Body() dto: CreateCatDto) {
    return this.commandBus.execute(new CreateCatCommand(dto.name, dto.age, dto.breed));
  }

  @Get()
  findAll(@Query('page') page: number, @Query('limit') limit: number) {
    return this.queryBus.execute(new GetCatsQuery(page, limit));
  }
}
// 9. 模块注册
@Module({
  imports: [CqrsModule],
  controllers: [CatsController],
  providers: [
    CreateCatHandler,
    GetCatsHandler,
    CatCreatedHandler,
    CatsSaga,
    CatsRepository,
  ],
})
export class CatsModule {}

6.3 NestJS 技术栈全景图

┌─────────────────────────────────────────────────────────────────┐
│                          客 户 端                                │
│           Web App    Mobile App    第三方服务    IoT 设备          │
└──────┬──────────────────┬───────────────┬──────────────┬────────┘
       │ HTTP/HTTPS        │ WebSocket      │ gRPC          │ MQTT
       ▼                  ▼               ▼              ▼
┌─────────────────────────────────────────────────────────────────┐
│                    API 网关 / BFF 层                              │
│                                                                 │
│  NestJS Application                                             │
│  ├── REST API + Swagger 文档(@nestjs/swagger)                   │
│  ├── GraphQL Federation Gateway(@nestjs/graphql + Apollo)       │
│  ├── WebSocket Gateway(@nestjs/websockets + Socket.IO)          │
│  │                                                              │
│  ├── 安全层                                                      │
│  │   ├── JWT 认证(@nestjs/jwt)                                  │
│  │   ├── RBAC/CASL 授权                                          │
│  │   ├── Helmet + CORS + CSRF                                   │
│  │   ├── 限流(@nestjs/throttler)                                │
│  │   └── 加密(crypto + bcrypt)                                  │
│  │                                                              │
│  └── 请求管线                                                    │
│      Middleware → Guard → Interceptor → Pipe → Handler → Filter │
└──────┬──────────────────┬───────────────┬───────────────────────┘
       │                  │               │
       ▼                  ▼               ▼
┌─────────────┐  ┌──────────────┐  ┌─────────────┐
│  用户服务     │  │  订单服务      │  │  支付服务    │
│  NestJS      │  │  NestJS       │  │  NestJS     │
│  TypeORM     │  │  Prisma       │  │  Mongoose   │
│  PostgreSQL  │  │  MySQL        │  │  MongoDB    │
│  CQRS        │  │  Event Driven │  │  Saga       │
└──────┬───────┘  └──────┬───────┘  └──────┬──────┘
       │                 │                 │
       └─────────────────┼─────────────────┘
                         ▼
┌─────────────────────────────────────────────────────────────────┐
│                       消息总线                                    │
│                                                                 │
│  RabbitMQ(可靠投递)  Kafka(流处理)  NATS(高吞吐)  Redis(轻量)  │
│                                                                 │
│  @MessagePattern('sum')        ← 请求-响应模式                    │
│  @EventPattern('user.created') ← 事件驱动模式                     │
└─────────────────────────────────────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────────────────────┐
│                      基础设施层                                   │
│                                                                 │
│  ┌───────────┐ ┌───────────┐ ┌──────────┐ ┌──────────────────┐ │
│  │  Redis     │ │  BullMQ   │ │  Cron    │ │  AsyncLocal      │ │
│  │  缓存      │ │  消息队列  │ │  定时任务 │ │  Storage(CLS)   │ │
│  │  Session   │ │  延迟任务  │ │  @Cron() │ │  请求上下文       │ │
│  └───────────┘ └───────────┘ └──────────┘ └──────────────────┘ │
│                                                                 │
│  ┌───────────┐ ┌───────────┐ ┌──────────┐ ┌──────────────────┐ │
│  │  Sentry   │ │  ELK      │ │Prometheus│ │  NestJS DevTools │ │
│  │  错误追踪  │ │  日志收集  │ │  指标监控 │ │  依赖图 + 调试   │ │
│  └───────────┘ └───────────┘ └──────────┘ └──────────────────┘ │
│                                                                 │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │  部署:Docker + Kubernetes + CI/CD + Health Checks         │  │
│  │  或 Serverless:AWS Lambda + @codegenie/serverless-express │  │
│  └───────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────┘

6.4 技术决策清单

决策点推荐方案备选方案决策依据
HTTP 引擎ExpressFastifyExpress 生态丰富;Fastify 性能高
ORMPrismaTypeORM / MikroORMPrisma 类型安全最强;TypeORM 最成熟
认证@nestjs/jwtPassport(多策略)JWT 简单直接;Passport 支持 OAuth2 等
缓存Redis + cache-manager内存缓存单实例用内存;多实例必须 Redis
队列BullMQ + RedisRabbitMQ / KafkaBullMQ 简单;RabbitMQ 可靠;Kafka 大规模
API 风格REST + SwaggerGraphQLREST 通用;GraphQL 适合复杂前端查询
微服务通信gRPC(内部 RPC)NATS / Kafka(事件)gRPC 强类型高性能;NATS 简单高吞吐
部署方式Docker + K8sServerless容器化主流;Serverless 适合低流量
日志JSON + ELKDatadog / SentryELK 自建;Datadog/Sentry 托管
请求上下文nestjs-clsScope.REQUESTCLS 无性能损耗;Scope 冒泡影响性能

七、课后实践

练习 1:Docker 部署(基础)

# 1. 编写 Dockerfile(多阶段构建)
# 2. 编写 .dockerignore
# 3. 编写 docker-compose.yml(应用 + PostgreSQL + Redis)
# 4. 构建并运行
docker-compose up --build
# 5. 验证 http://localhost:3000/health

练习 2:健康检查(基础)

// 1. 安装 @nestjs/terminus
// 2. 创建 HealthModule + HealthController
// 3. 添加 Database + Memory 健康指标
// 4. 创建自定义 RedisHealthIndicator
// 5. 验证 GET /health 返回正常

练习 3:优雅关闭与 Sentry(中阶)

// 1. 启用 enableShutdownHooks()
// 2. 实现 onModuleDestroy() 清理数据库连接
// 3. 配置 forceCloseConnections: true
// 4. 集成 Sentry 错误追踪
// 5. 主动抛出异常,验证 Sentry 收到报告

练习 4:CQRS 实践(高阶)

// 1. 安装 @nestjs/cqrs
// 2. 将 CatsService.create() 改为 CreateCatCommand + Handler
// 3. 将 CatsService.findAll() 改为 GetCatsQuery + Handler
// 4. 创建 CatCreatedEvent + Handler(打印日志)
// 5. 创建 Saga:猫创建后自动发送通知

练习 5:性能对比(资深)

# 1. 分别用 tsc 和 SWC 编译项目,对比编译时间
# 2. 分别用 Express 和 Fastify 启动,用 autocannon 压测
#    npx autocannon -c 100 -d 10 http://localhost:3000/cats
# 3. 记录 RPS、延迟 P99,对比两个平台的差异
# 4. 阅读 FastifyAdapter 源码,理解平台抽象层设计

八、本课知识点总结

知识点要点
构建npm run builddist/main.jsNODE_ENV=production
Docker多阶段构建,非 root 用户,.dockerignore
健康检查@nestjs/terminus,TerminusModule,内置 5 种指标,自定义 HealthIndicator
环境变量ConfigService,不硬编码,运行时注入
JSON 日志ConsoleLogger({ json: true }),Correlation ID 贯穿全链路
优雅关闭forceCloseConnections + enableShutdownHooks()
HTTPShttpsOptions: { key, cert },HTTP 重定向 + HTTPS
全局前缀setGlobalPrefix('api', { exclude: ['health'] })
Raw Body{ rawBody: true } 用于 Webhook 签名验证
SWC~20x 编译加速,不支持 Swagger Plugin
Fastify~2x 吞吐提升,需注意 0.0.0.0 监听
SentrySentryModule.forRoot() + SentryGlobalFilter
水平扩展无状态设计 + 负载均衡 + Redis Session/Cache
Docker Compose多服务编排 + 健康检查 + 依赖等待
CI/CDLint → Test → Build → Push → Deploy
AWS Lambda@codegenie/serverless-express + LazyModuleLoader
nest-commanderCommandRunner + @Command + @Option
nestjs-clsAsyncLocalStorage 替代 Scope.REQUEST
常见错误"Cannot resolve dependency" → providers/forwardRef/NEST_DEBUG
DevTools依赖图、路由导航、Playground、性能分析
演进路径单体 → 混合 → 微服务集群 → Federation
CQRSCommandBus → Handler → EventBus → EventHandler,QueryBus → Handler
@Saga事件驱动命令链
技术决策Express/Fastify、Prisma/TypeORM、gRPC/NATS、Docker/Serverless

九、课程总结 — 20 课 NestJS 全栈之旅

恭喜你完成了 NestJS 全栈深入课程的全部 20 课。让我们回顾这段旅程:

学习路线全景

第一阶段:核心基础(第 1-4 课)
  第 1 课  走进 NestJS        → 理念、CLI、项目创建
  第 2 课  Controller         → 路由、参数、版本控制
  第 3 课  Provider 与 DI     → 依赖注入、自定义 Provider
  第 4Module             → 模块化、动态模块、Monorepo

第二阶段:请求管线(第 5-8 课)
  第 5 课  Middleware + 异常    → 中间件、异常过滤器
  第 6 课  Pipe + 验证          → 管道、class-validator、Zod
  第 7 课  Guard + Interceptor  → 守卫、拦截器、ExecutionContext
  第 8 课  Custom Decorator     → 自定义装饰器、Discovery Service

第三阶段:DI 深入(第 9 课)
  第 9 课  注入作用域与生命周期   → Scope、ModuleRef、forwardRef、生命周期钩子

第四阶段:数据与安全(第 10-12 课)
  第 10 课  数据库集成           → TypeORM、Prisma、Mongoose、序列化
  第 11 课  认证与授权           → JWT、Passport、RBAC、CASL
  第 12 课  安全加固             → Helmet、CORS、CSRF、限流、加密

第五阶段:实用技术(第 13-15 课)
  第 13 课  配置、日志与事件      → ConfigModule、Logger、EventEmitter
  第 14 课  缓存、队列与定时任务   → cache-manager、BullMQ、@Cron15 课  文件、HTTP 与其他     → 上传、流式、SSE、MVC

第六阶段:通信与 API(第 16-19 课)
  第 16 课  WebSocket           → Socket.IO、适配器、增强器
  第 17 课  微服务               → 7 种传输层、混合应用、自定义传输
  第 18 课  GraphQL             → Code First、Federation、订阅
  第 19 课  API 文档与测试       → Swagger、单元测试、E2E 测试

第七阶段:生产(第 20 课)
  第 20 课  生产部署与架构设计    → Docker、CQRS、Serverless、技术全景图

核心能力矩阵

能力层次掌握内容可以做什么
基础Controller、Service、Module、Pipe、Guard独立开发标准 REST API
中阶动态模块、Interceptor、配置、缓存、队列开发生产级企业应用
高阶微服务、GraphQL、WebSocket、CQRS设计复杂分布式系统
资深源码原理、平台抽象、DI 容器扩展框架、贡献源码
架构技术选型、演进策略、质量保障主导技术方案和团队建设

持续学习建议

  1. 实践:选择一个真实项目,从单体开始,逐步应用课程中的技术
  2. 源码:阅读 packages/core/ 目录,重点关注 DI 容器和请求管线
  3. 社区:关注 NestJS GitHub 仓库的 Release Notes,跟踪新特性
  4. 扩展:探索课程未涵盖的主题 — Prisma 高级、Kafka Streams、K8s Operator

NestJS 的核心价值在于:用 Angular 式的架构思维构建 Node.js 后端。掌握了模块化 + DI + 装饰器这三大支柱,你就掌握了 NestJS 的灵魂。无论技术如何演进,这些架构思想都将持续受用。