Skip to content

NestJS 微服务架构概览

一、单体 vs 微服务

单体应用:所有模块打包在一个进程中部署,简单但扩展困难。

微服务:将系统拆分为多个独立进程,每个服务有自己的数据库,通过网络通信。

单体应用:
┌─────────────────────────────┐
│  UserModule  PostModule     │
│  AuthModule  EmailModule    │  → 一个进程,一个数据库
└─────────────────────────────┘

微服务:
┌───────────┐  ┌───────────┐  ┌───────────┐
│ user-svc  │  │ post-svc  │  │ email-svc │  → 各自进程、各自数据库
└───────────┘  └───────────┘  └───────────┘
      ↑               ↑              ↑
      └───────── 消息队列/RPC ────────┘
维度单体微服务
复杂度高(网络、数据一致性)
独立部署不可以可以(每个服务独立发布)
独立扩展不可以可以(按需水平扩展)
故障隔离差(一处挂全挂)好(服务间隔离)
技术选型统一各自选择最适合的栈
适合场景中小型应用、快速迭代大型系统、高并发、多团队

二、NestJS 微服务核心抽象

NestJS 将传输层抽象为可互换的适配器——业务代码不关心底层通信协议

typescript
// ── 服务端:启动纯微服务进程 ────────────────────
// user-service/src/main.ts
import { NestFactory } from '@nestjs/core';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';

async function bootstrap() {
  const app = await NestFactory.createMicroservice<MicroserviceOptions>(AppModule, {
    transport: Transport.REDIS,
    options: {
      host: process.env.REDIS_HOST ?? 'localhost',
      port: parseInt(process.env.REDIS_PORT ?? '6379'),
    },
  });
  await app.listen();
  console.log('user-service is listening');
}
bootstrap();
typescript
// ── 客户端:在 Gateway 中连接微服务 ─────────────
// gateway/src/app.module.ts
@Module({
  imports: [
    ClientsModule.registerAsync([
      {
        name: 'USER_SERVICE',
        inject: [ConfigService],
        useFactory: (config: ConfigService) => ({
          transport: Transport.REDIS,
          options: {
            host: config.get('REDIS_HOST'),
            port: config.get('REDIS_PORT'),
          },
        }),
      },
    ]),
  ],
})
export class GatewayModule {}

三、传输层对比与选型

传输层适用场景特点
TCP内置内部服务同步调用简单直连,无持久化
Redisioredis轻量异步通信Pub/Sub,简单配置
RabbitMQamqplib企业消息队列可靠投递、死信队列、路由规则
Kafkakafkajs高吞吐事件流分区、消费组、日志持久化
gRPC@grpc/grpc-js高性能内部 RPC强类型(Protobuf)、双向流
NATSnats轻量级云原生低延迟,Kubernetes 友好

选型建议:

  • 开发/演示:Redis(零配置)
  • 生产关键业务:RabbitMQ(可靠投递,消息确认)
  • 日志/大数据管道:Kafka(高吞吐,持久化)
  • 服务间同步调用:gRPC(高性能,类型安全)

四、混合应用(HTTP + 微服务)

API Gateway 通常既暴露 HTTP 接口(对外),又作为微服务客户端(对内):

typescript
// gateway/src/main.ts
async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // 同时启动一个微服务监听器(接收来自其他服务的消息)
  app.connectMicroservice<MicroserviceOptions>({
    transport: Transport.REDIS,
    options: { host: 'localhost', port: 6379 },
  });

  await app.startAllMicroservices();  // 先启动微服务监听
  await app.listen(3000);            // 再启动 HTTP 服务器
  console.log('Gateway: HTTP on :3000 + microservice on Redis');
}

五、服务发现与健康检查

bash
npm install @nestjs/terminus
typescript
// health/health.controller.ts
import { HealthCheck, HealthCheckService, TypeOrmHealthIndicator, MicroserviceHealthIndicator } from '@nestjs/terminus';

@Controller('health')
export class HealthController {
  constructor(
    private health: HealthCheckService,
    private db: TypeOrmHealthIndicator,
    private microservice: MicroserviceHealthIndicator,
  ) {}

  @Get()
  @HealthCheck()
  check() {
    return this.health.check([
      // 数据库健康
      () => this.db.pingCheck('database'),
      // 依赖的微服务健康
      () => this.microservice.pingCheck<TcpClientOptions>('user-service', {
        transport: Transport.TCP,
        options: { host: 'user-service', port: 3001 },
      }),
    ]);
  }
}

六、本仓库实战项目结构

practice/05-microservices/
├── docker-compose.yml          # 统一编排所有服务
├── gateway/                    # API Gateway(HTTP :3000)
│   ├── src/
│   │   ├── users/              # 代理到 user-service
│   │   ├── posts/              # 代理到 content-service
│   │   └── auth/               # JWT 验证(在 Gateway 层)
│   └── Dockerfile
├── user-service/               # 用户服务(微服务,监听 Redis)
│   ├── src/
│   │   └── users/
│   └── Dockerfile
└── content-service/            # 内容服务(微服务,监听 Redis)
    ├── src/
    │   └── posts/
    └── Dockerfile
yaml
# docker-compose.yml
version: '3.8'
services:
  redis:
    image: redis:7-alpine
    ports: ['6379:6379']

  user-service:
    build: ./user-service
    environment:
      REDIS_HOST: redis
      DATABASE_URL: postgres://...
    depends_on: [redis, postgres]

  content-service:
    build: ./content-service
    environment:
      REDIS_HOST: redis
    depends_on: [redis]

  gateway:
    build: ./gateway
    ports: ['3000:3000']
    environment:
      REDIS_HOST: redis
      JWT_SECRET: ${JWT_SECRET}
    depends_on: [redis, user-service, content-service]

七、微服务拆分原则

  1. 按业务能力拆分(不按技术层):user-serviceorder-service 而非 dao-service
  2. 每个服务拥有自己的数据库:数据隔离是微服务的核心约束
  3. 服务大小适中:团队能够完全理解和维护("两个披萨"原则)
  4. 先做好单体,再拆分:过早拆分是反模式,分布式系统复杂度极高
  5. 定义清晰的服务契约:消息格式(Schema)应独立维护,避免耦合

常见错误

错误原因解决
微服务连接失败但没有错误日志TCP/Redis 传输层连接超时静默失败监听 microservice.connect() 的异常,或加连接超时配置
消息发送后没有响应(请求超时)@MessagePattern 未在目标服务注册确认消息名称一致,检查目标微服务是否正常启动
混合应用 HTTP 和微服务端口冲突connectMicroservicelisten 端口相同微服务用独立端口,或使用不需要端口的传输层(如 Redis)

NestJS 深度学习体系