728x90
반응형
728x170

마이크로서비스(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의 마이크로서비스 모듈을 활용하면, 마이크로서비스 아키텍처를 기반으로 한 애플리케이션을 효과적으로 개발하고 관리할 수 있어요. 각 서비스가 독립적으로 기능하면서도 효율적으로 통신할 수 있는 구조를 구축함으로써, 애플리케이션의 확장성, 유연성, 복원력을 대폭 향상시킬 수 있습니다.

 

마이크로 서비스를 활용해보시려는 분들에게 도움이 되셨길 바랍니다.

728x90
반응형
그리드형
Bami