正在加载,请稍候…

NestJS Microservices: Build Scalable Distributed Systems

Build production-ready microservices with NestJS — message brokers, gRPC, event sourcing, service discovery, and inter-service communication patterns.

NestJS Microservices Architecture

NestJS provides first-class support for microservices via transport layers — from TCP to message queues.

Setting Up a Microservice

npm install @nestjs/microservices
// main.ts - Microservice bootstrap
import { NestFactory } from '@nestjs/core';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.createMicroservice<MicroserviceOptions>(
    AppModule,
    {
      transport: Transport.TCP,
      options: {
        host: '0.0.0.0',
        port: 3001,
      },
    },
  );
  await app.listen();
  console.log('Microservice is listening on port 3001');
}
bootstrap();

Message Patterns

// users.controller.ts
import { Controller } from '@nestjs/common';
import { MessagePattern, Payload } from '@nestjs/microservices';
import { UsersService } from './users.service';

@Controller()
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @MessagePattern({ cmd: 'get_user' })
  async getUser(@Payload() data: { id: string }) {
    return this.usersService.findById(data.id);
  }

  @MessagePattern({ cmd: 'create_user' })
  async createUser(@Payload() createUserDto: CreateUserDto) {
    return this.usersService.create(createUserDto);
  }
}

RabbitMQ Transport

// app.module.ts - RabbitMQ setup
import { Module } from '@nestjs/common';
import { ClientsModule, Transport } from '@nestjs/microservices';

@Module({
  imports: [
    ClientsModule.register([
      {
        name: 'ORDERS_SERVICE',
        transport: Transport.RMQ,
        options: {
          urls: ['amqp://localhost:5672'],
          queue: 'orders_queue',
          queueOptions: { durable: false },
        },
      },
    ]),
  ],
})
export class AppModule {}
// Sending messages from a client
import { Inject } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';

export class OrdersService {
  constructor(
    @Inject('ORDERS_SERVICE') private ordersClient: ClientProxy,
  ) {}

  async createOrder(dto: CreateOrderDto) {
    return this.ordersClient.send({ cmd: 'create_order' }, dto).toPromise();
  }

  async emitOrderCreated(order: Order) {
    this.ordersClient.emit('order_created', order);
  }
}

gRPC Transport

// main.ts - gRPC microservice
const app = await NestFactory.createMicroservice<MicroserviceOptions>(
  AppModule,
  {
    transport: Transport.GRPC,
    options: {
      package: 'users',
      protoPath: join(__dirname, './users.proto'),
      url: 'localhost:5000',
    },
  },
);
// users.proto
syntax = "proto3";

package users;

service UsersService {
  rpc FindOne (UserById) returns (User);
  rpc FindAll (Empty) returns (UsersResponse);
}

message UserById {
  int32 id = 1;
}

message User {
  int32 id = 1;
  string name = 2;
  string email = 3;
}

Event-Driven with Redis Pub/Sub

// Using Redis for event-driven architecture
const app = await NestFactory.createMicroservice<MicroserviceOptions>(
  AppModule,
  {
    transport: Transport.REDIS,
    options: {
      host: 'localhost',
      port: 6379,
    },
  },
);

Exception Filters in Microservices

import { Catch, RpcExceptionFilter } from '@nestjs/common';
import { Observable, throwError } from 'rxjs';
import { RpcException } from '@nestjs/microservices';

@Catch(RpcException)
export class ExceptionFilter implements RpcExceptionFilter<RpcException> {
  catch(exception: RpcException): Observable<any> {
    return throwError(() => exception.getError());
  }
}

Health Checks

import { HealthCheckService, MicroserviceHealthIndicator } from '@nestjs/terminus';
import { Transport } from '@nestjs/microservices';

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

  @Get()
  @HealthCheck()
  check() {
    return this.health.check([
      () =>
        this.microservice.pingCheck('orders-service', {
          transport: Transport.TCP,
          options: { host: 'orders-service', port: 3001 },
        }),
    ]);
  }
}

Inter-Service Communication Patterns

Request-Response

Use send() for synchronous operations expecting a reply.

Fire-and-Forget

Use emit() for events where no response is needed.

Sagas (Distributed Transactions)

Implement the Saga pattern for multi-service transactions:

// Order saga: debit account -> reserve inventory -> confirm order
async createOrderSaga(orderId: string) {
  try {
    await this.paymentService.debit(orderId);
    await this.inventoryService.reserve(orderId);
    await this.ordersService.confirm(orderId);
  } catch (err) {
    // Compensating transactions
    await this.inventoryService.release(orderId);
    await this.paymentService.refund(orderId);
    throw err;
  }
}

Best Practices

  • Use DTOs + class-validator for all inter-service messages
  • Add correlation IDs to trace requests across services
  • Implement circuit breakers with libraries like opossum
  • Version your APIs to allow rolling updates
  • Use shared libraries for common DTOs and event types