2. NestJS 微服务基础:创建微服务应用、传输层与通信模式

在构建分布式系统时,微服务架构通过将单一应用拆分为多个独立部署的服务,实现了高内聚、低耦合。NestJS 作为一款渐进式 Node.js 框架,原生提供了强大的微服务支持,允许开发者使用统一的编程模型构建异构系统。本章将深入讲解 NestJS 微服务的核心概念,包括如何创建微服务应用、四种主流传输层的特性对比,以及三种基本的微服务通信模式。

2.1 创建 NestJS 微服务应用

NestJS 微服务应用与常规 HTTP 应用在架构上有所不同。微服务应用通常不直接监听 HTTP 端口,而是通过特定的传输层监听消息。创建过程分为两步:创建微服务实例与配置传输层策略。

2.1.1 基础创建流程

首先,使用 @nestjs/microservices 包中的 MicroserviceOptions 接口定义传输层选项。以下示例展示了如何创建一个基于 TCP 传输的微服务应用:

import { NestFactory } from '@nestjs/core';
import { Transport, MicroserviceOptions } from '@nestjs/microservices';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.createMicroservice<MicroserviceOptions>(
    AppModule,
    {
      transport: Transport.TCP,
      options: {
        host: '127.0.0.1',
        port: 3001,
      },
    },
  );
  await app.listen();
}
bootstrap();

关键点说明:

  • NestFactory.createMicroservice:创建微服务实例,而非 HTTP 实例。
  • Transport.TCP:指定传输层协议为 TCP。
  • options:配置传输层参数,如主机地址和端口。

2.1.2 混合应用模式

在实际项目中,微服务节点往往需要同时提供 HTTP API 和内部微服务通信能力。NestJS 支持混合应用模式,即一个应用同时监听 HTTP 端口和微服务传输层端口:

import { NestFactory } from '@nestjs/core';
import { Transport, MicroserviceOptions } from '@nestjs/microservices';
import { AppModule } from './app.module';

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

  // 连接微服务传输层
  app.connectMicroservice<MicroserviceOptions>({
    transport: Transport.TCP,
    options: { port: 3001 },
  });

  await app.startAllMicroservices();
  await app.listen(3000);
}
bootstrap();
实践建议:混合模式常用于 API 网关服务,它对外暴露 HTTP 端点,对内通过微服务传输层与业务服务通信。这种模式可以有效隔离外部请求与内部服务调用。

2.2 传输层:TCP、Redis、RabbitMQ、Kafka

传输层是微服务通信的基石,决定了消息如何在不同服务之间传递。NestJS 内置支持四种主流传输层:TCP、Redis、RabbitMQ 和 Kafka。每种传输层都有其适用场景和性能特征。

2.2.1 传输层对比

传输层 通信模型 消息持久化 适用场景 性能
TCP 点对点 无 开发环境、简单内部服务 高(低延迟)
Redis 发布/订阅 无(默认) 轻量级广播、缓存同步 高
RabbitMQ 队列 + 交换器 支持 任务队列、可靠消息传递 中高
Kafka 分区日志 支持(日志持久化) 事件流、日志聚合、大数据 高(吞吐量优先)

2.2.2 各传输层配置示例

Redis 传输层配置:

const app = await NestFactory.createMicroservice<MicroserviceOptions>(
  AppModule,
  {
    transport: Transport.REDIS,
    options: {
      host: 'localhost',
      port: 6379,
    },
  },
);

RabbitMQ 传输层配置:

const app = await NestFactory.createMicroservice<MicroserviceOptions>(
  AppModule,
  {
    transport: Transport.RMQ,
    options: {
      urls: ['amqp://localhost:5672'],
      queue: 'user-service-queue',
      queueOptions: {
        durable: true,
      },
    },
  },
);

Kafka 传输层配置:

const app = await NestFactory.createMicroservice<MicroserviceOptions>(
  AppModule,
  {
    transport: Transport.KAFKA,
    options: {
      client: {
        brokers: ['localhost:9092'],
      },
      consumer: {
        groupId: 'user-consumer-group',
      },
    },
  },
);
注意:选择传输层时,需考虑消息的持久性要求。TCP 和 Redis 默认不持久化消息,服务重启后未处理的消息会丢失。RabbitMQ 和 Kafka 支持持久化,适合对数据一致性要求较高的场景。

2.3 微服务通信模式

NestJS 微服务支持三种核心通信模式:请求-响应、基于消息的事件驱动、以及流式处理。理解这些模式是设计微服务交互的基础。

2.3.1 请求-响应模式(Request-Response)

这是最常用的同步通信模式。客户端发送请求并等待服务端响应。在 NestJS 中,通过 @MessagePattern() 装饰器定义消息处理程序。

服务端定义:

import { Controller } from '@nestjs/common';
import { MessagePattern } from '@nestjs/microservices';

@Controller()
export class UserController {
  @MessagePattern({ cmd: 'get_user' })
  getUser(data: { id: number }): any {
    // 模拟查询用户
    return { id: data.id, name: 'Alice' };
  }
}

客户端调用:

import { Injectable, Inject } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';

@Injectable()
export class UserService {
  constructor(@Inject('USER_SERVICE') private client: ClientProxy) {}

  async getUser(id: number) {
    return this.client.send({ cmd: 'get_user' }, { id }).toPromise();
  }
}

2.3.2 事件驱动模式(Event-Driven)

事件驱动模式采用发布/订阅机制,发送方发布事件,接收方异步处理。使用 @EventPattern() 装饰器定义事件处理程序。

事件发布者:

this.client.emit('user_created', { userId: 1, email: 'alice@example.com' });

事件消费者:

import { Controller } from '@nestjs/common';
import { EventPattern } from '@nestjs/microservices';

@Controller()
export class NotificationController {
  @EventPattern('user_created')
  handleUserCreated(data: { userId: number; email: string }) {
    // 发送欢迎邮件
    console.log(`Sending welcome email to ${data.email}`);
  }
}

2.3.3 流式处理模式(Streaming)

流式处理适用于处理大量连续数据,如日志收集或实时指标。NestJS 通过 RxJS Observable 支持流式响应。

import { Controller } from '@nestjs/common';
import { MessagePattern } from '@nestjs/microservices';
import { Observable, interval } from 'rxjs';
import { map } from 'rxjs/operators';

@Controller()
export class MetricsController {
  @MessagePattern({ cmd: 'stream_metrics' })
  streamMetrics(): Observable<any> {
    return interval(1000).pipe(
      map(() => ({ timestamp: Date.now(), cpu: Math.random() * 100 })),
    );
  }
}

2.4 通信模式对比与选择

模式 同步/异步 耦合度 典型场景
请求-响应 同步 高(调用方依赖响应) 查询用户信息、订单状态
事件驱动 异步 低(发布者不关心消费者) 用户注册通知、库存更新
流式处理 异步 中(持续连接) 实时监控、日志流
架构决策提示:在微服务设计中,优先使用事件驱动模式来降低服务间的直接依赖。请求-响应模式应仅限于需要即时返回结果的场景,如查询操作。流式处理则适用于需要持续推送数据的场景。

2.5 本章小结

本章介绍了 NestJS 微服务的基础知识,包括如何创建微服务应用、四种传输层的配置与对比,以及三种核心通信模式。掌握这些基础是后续学习熔断降级和依赖反转设计的前提。在实际项目中,应根据业务需求、性能要求和可靠性目标选择合适的传输层和通信模式组合。