NestJS có hỗ trợ tích hợp cho microservices với nhiều transport layer khác nhau: TCP, Redis, NATS, RabbitMQ, Kafka, gRPC. Bài này hướng dẫn xây dựng hệ thống microservices đơn giản với TCP và Redis.
1. Kiến trúc Microservices trong NestJS
[API Gateway / Client]
↓ HTTP request
[NestJS App] ─── TCP ──→ [User Service :3001]
─── TCP ──→ [Order Service :3002]
─── Redis → [Notification Service]
NestJS hỗ trợ hai kiểu giao tiếp:
- Request-Response: Client gửi, đợi response (như HTTP)
- Event: Client publish event, không đợi (fire & forget)
2. TCP Transport — Request/Response
Microservice (Server)
// user-service/main.ts
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('User Microservice đang chạy trên port 3001');
}
bootstrap();
// user-service/users.controller.ts
import { Controller } from '@nestjs/common';
import { MessagePattern, Payload } from '@nestjs/microservices';
@Controller()
export class UsersController {
@MessagePattern({ cmd: 'get_user' })
async getUser(@Payload() data: { id: string }) {
return { id: data.id, name: 'Nguyen Van A', email: 'a@example.com' };
}
@MessagePattern({ cmd: 'create_user' })
async createUser(@Payload() dto: { name: string; email: string }) {
// Lưu vào DB...
return { id: 'new-id', ...dto, createdAt: new Date() };
}
@MessagePattern({ cmd: 'get_users_by_ids' })
async getUsersByIds(@Payload() data: { ids: string[] }) {
return data.ids.map(id => ({ id, name: `User ${id}` }));
}
}
Client — Gọi Microservice
// api-gateway/app.module.ts
import { ClientsModule, Transport } from '@nestjs/microservices';
@Module({
imports: [
ClientsModule.register([
{
name: 'USER_SERVICE',
transport: Transport.TCP,
options: { host: 'localhost', port: 3001 },
},
{
name: 'ORDER_SERVICE',
transport: Transport.TCP,
options: { host: 'localhost', port: 3002 },
},
]),
],
})
export class AppModule {}
// api-gateway/users.controller.ts
import { Inject, Controller, Get, Post, Body, Param } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';
import { firstValueFrom } from 'rxjs';
@Controller('users')
export class UsersController {
constructor(
@Inject('USER_SERVICE') private userService: ClientProxy,
) {}
@Get(':id')
async getUser(@Param('id') id: string) {
// Gọi microservice và đợi response
return firstValueFrom(
this.userService.send({ cmd: 'get_user' }, { id }),
);
}
@Post()
async createUser(@Body() dto: { name: string; email: string }) {
return firstValueFrom(
this.userService.send({ cmd: 'create_user' }, dto),
);
}
}
3. Redis Transport — Event-based
Redis phù hợp cho event-driven: publish event không cần đợi response.
// notification-service/main.ts
const app = await NestFactory.createMicroservice<MicroserviceOptions>(AppModule, {
transport: Transport.REDIS,
options: {
host: process.env.REDIS_HOST ?? 'localhost',
port: Number(process.env.REDIS_PORT ?? 6379),
},
});
// notification-service/notification.controller.ts
import { EventPattern, Payload } from '@nestjs/microservices';
@Controller()
export class NotificationController {
@EventPattern('user.registered')
async handleUserRegistered(@Payload() data: { userId: string; email: string }) {
console.log(`Gửi welcome email đến ${data.email}`);
// await emailService.sendWelcome(data.email);
}
@EventPattern('order.placed')
async handleOrderPlaced(@Payload() data: { orderId: string; userId: string }) {
console.log(`Gửi xác nhận đơn hàng ${data.orderId}`);
}
}
// api-gateway — Publish event (không đợi)
@Inject('NOTIFICATION_SERVICE') private notifService: ClientProxy;
// Sau khi user đăng ký
this.notifService.emit('user.registered', { userId: user.id, email: user.email });
4. Kết hợp HTTP API + Microservices
// api-gateway/orders.controller.ts — Orchestrate nhiều microservice
@Post()
async createOrder(@Body() dto: CreateOrderDto, @CurrentUser() user: User) {
// 1. Validate user
const userProfile = await firstValueFrom(
this.userService.send({ cmd: 'get_user' }, { id: user.id }),
);
// 2. Tạo order
const order = await firstValueFrom(
this.orderService.send({ cmd: 'create_order' }, { ...dto, userId: user.id }),
);
// 3. Notify (fire & forget — không cần đợi)
this.notifService.emit('order.placed', { orderId: order.id, userId: user.id });
return order;
}
5. Error Handling trong Microservices
// Microservice — throw exception
import { RpcException } from '@nestjs/microservices';
@MessagePattern({ cmd: 'get_user' })
async getUser(@Payload() data: { id: string }) {
const user = await this.usersService.findById(data.id);
if (!user) throw new RpcException({ message: 'User not found', status: 404 });
return user;
}
// Client — catch exception
try {
const user = await firstValueFrom(
this.userService.send({ cmd: 'get_user' }, { id }).pipe(
catchError(err => throwError(() => new NotFoundException(err.message))),
),
);
} catch (e) {
throw new NotFoundException('Người dùng không tồn tại');
}
6. Kết luận
NestJS Microservices đơn giản hóa giao tiếp service-to-service:
- TCP: Request/Response — phù hợp khi cần đợi kết quả
- Redis: Event-based — phù hợp cho notification, background tasks
send()= request/response (có await),emit()= fire & forget@MessagePattern= xử lý request,@EventPattern= xử lý event
Bắt đầu với monolith, refactor sang microservices khi thực sự cần — đừng over-engineer từ đầu.