마이크로서비스(Microservices)?
마이크로서비스는 애플리케이션을 작고, 독립적으로 배포 가능한 서비스로 나누는 아키텍처 스타일을 말하는데
이 모듈을 사용하여, 독립적으로 배포 가능한 작은 서비스들을 구축하고, 이 서비스들 간의 효율적인 통신을 관리할 수 있게 해줍니다.
대표적으로 TCP, Redis, MQTT, NATS, 드의 다양한 메시지 전달 매커니즘을 지원하여, 마이크로 서비스 간의 비동기 통신을 쉽게 구현 할 수 있게 해줍니다.
그래서 애플리케이션의 각 기능을 독립된 서비스로 분리하고 싶을 때, 서비스를 개별적으로 업데이트 하거나 확장하고 싶을 때, 서비스마다 가장 적합한 기술 스택을 사용하고 싶을 때 자주 사용합니다.
마이크로 서비스의 장점
시스템의 특정 부분만 확장할 수 있기 떄문에 자원을 보다 효율적으로 사용할 수 있게 되고,
서비스마다 다른 기술 스택을 사용할 수 있어 기술 선택의 유연성이 높아지게 되고,
독립적으로 서비스를 나누었기 때문에 하나의 서비스에 문제가 발생해도 전체 시스템에 영향을 미치지 않아 시스템의 전반적인 안정성이 향상됩니다.
자, 이제 Nest에서 마이크로서비스를 어떻게 사용하는 지 예시를 알아보도록 하겠습니다.
TCP를 사용한 간단한 마이크로서비스 통신 예시
math.service.ts
import { Controller } from '@nestjs/common';
import { MessagePattern } from '@nestjs/microservices';
@Controller()
export class MathService {
@MessagePattern({ cmd: 'add' })
add(data: number[]): number {
return (data || []).reduce((a, b) => a + b);
}
}
app.module.ts
import { Module } from '@nestjs/common';
import { MicroservicesModule } from '@nestjs/microservices';
import { MathService } from './math.service';
@Module({
imports: [MicroservicesModule],
controllers: [MathService],
})
export class AppModule {}
이 예시에서 MathService 서비스는 add라는 커맨드를 통해 수신된 데이터의 합계를 계산하고 반환하는데요.
@MessagePattern 데코레이터를 사용하여, 특정 메시지 패턴에 반응하도록 서비스를 구성하게 됩니다.
RabbitMQ를 사용한 NestJS 이벤트 주도 마이크로서비스 예시
주문을 처리하는 주문 서비스(Order Service)와 특정 트리거(예: 주문 배치)에 따라 사용자에게 알림을 보내는 알림 서비스(Notification Service)가 있는 시스템을 간단하게 구축해보겠습니다.
먼저 NestJS와 RabbitMQ 통합을 위해 필요한 패키지를 설치해줍니다.
npm install @nestjs/microservices amqplib amqp-connection-manager
이제 주문 서비스에 이벤트 발행 설정해보겠습니다.
새 주문이 들어올 때마다 주문 서비스는 RabbitMQ 교환소(exchange)에 메시지(이벤트)를 발행하게 됩니다.
order.service.ts파일을 생성하셔서 주문 이벤트를 발행하는 메소드를 설정해보죠.
import { Injectable } from '@nestjs/common';
import { ClientProxy, ClientProxyFactory, Transport } from '@nestjs/microservices';
@Injectable()
export class OrderService {
private client: ClientProxy;
constructor() {
this.client = ClientProxyFactory.create({
transport: Transport.RMQ,
options: {
urls: ['amqp://localhost:5672'],
queue: 'orders_queue',
queueOptions: { durable: false },
},
});
}
async createOrder(order: any) {
await this.client.emit('order_created', order);
}
}
이 메소드는 ClientProxy를 사용해 새 주문이 생성될 때마다 RabbitMQ의 orders_queue 큐에 order_created 이벤트를 발행하게 됩니다.
이제 알림 서비스가 이벤트를 듣도록 설정되도록 해보겠습니다.
알림 서비스는 orders_queue 큐에서 order_created 이벤트를 듣고, 알림을 보내는 등의 작업을 수행하도록 만들어보겠습니다.
notification.service.ts에서 들어오는 주문 이벤트를 처리하는 메소드를 설정해보죠.
import { Controller } from '@nestjs/common';
import { EventPattern } from '@nestjs/microservices';
@Controller()
export class NotificationService {
@EventPattern('order_created')
async handleOrderCreated(data: Record<string, any>) {
console.log('Order received:', data);
// 알림 로직 구현
}
}
@EventPattern 데코레이터를 사용해 이 서비스는 order_created 이벤트를 듣고 받은 주문 데이터를 로그합니다.
(실제 구현에서는 콘솔 로그 대신 알림을 보내는 로직으로 대체됩니다.)
마이크로서비스 사용 시 주의할 점
먼저 서비스 간 통신은 네트워크 지연과 메시지 손실의 가능성을 고려해야 하는데 이러한 문제를 메시지 큐, 이벤트 버스 등을 사용하여 완화할 수 있어요.
마이크로서비스 간 데이터 공유 시 일관성을 유지하는 것이 중요한데 이를 위해 이벤트 소싱, CQRS(명령 조회 책임 분리) 같은 패턴을 고려 해볼 수 있어요.
마이크로서비스 아키텍처는 시스템의 복잡성을 증가시킬 수 있는데 서비스의 수가 많아질수록 관리가 어려워질 수 있으므로, 서비스 메쉬, API 게이트웨이 등을 활용하여 이를 관리해주어야 해요.
오늘은 NestJS의 마이크로서비스에 대해 알아보았습니다. NestJS의 마이크로서비스 모듈을 활용하면, 마이크로서비스 아키텍처를 기반으로 한 애플리케이션을 효과적으로 개발하고 관리할 수 있어요. 각 서비스가 독립적으로 기능하면서도 효율적으로 통신할 수 있는 구조를 구축함으로써, 애플리케이션의 확장성, 유연성, 복원력을 대폭 향상시킬 수 있습니다.
마이크로 서비스를 활용해보시려는 분들에게 도움이 되셨길 바랍니다.
'프로그래밍(Basic) > NestJS' 카테고리의 다른 글
[바미] Nest - Websocket 구현 (0) | 2024.03.14 |
---|---|
[바미] Nest - 파이프(Pipes) (0) | 2024.03.08 |
[바미] NestJS - 예외 필터(Exception Filters) (0) | 2024.03.07 |
[바미] NestJS - 가드(Guards) (0) | 2024.03.06 |
[바미] NestJS - 인터셉터(Interceptors) (0) | 2024.03.05 |