기록

RabbitMQ와 스프링 부트를 활용한 간단한 메시징 시스템 구축하기 본문

Web/Spring

RabbitMQ와 스프링 부트를 활용한 간단한 메시징 시스템 구축하기

youngyin 2024. 12. 8. 00:00

시작하면서

RabbitMQ는 오픈 소스 메시지 브로커로, 애플리케이션 간에 메시지를 안전하게 전달하는 역할을 합니다. RabbitMQ는 메시지 큐를 이용해 비동기 통신을 쉽게 처리할 수 있어, 애플리케이션이 서로 독립적으로 동작하면서도 필요한 데이터를 주고받을 수 있게 도와줍니다. 이번 포스팅에서는 RabbitMQ의 주요 개념을 이해하고, 스프링 부트를 이용해 간단한 메시징 시스템을 구현하는 과정을 소개하겠습니다.

RabbitMQ의 주요 개념

RabbitMQ를 제대로 이해하려면 몇 가지 핵심 구성 요소들을 알아야 합니다. RabbitMQ는 여러 애플리케이션 간에 안전하고 효율적으로 메시지를 교환하기 위해 사용하는 메시지 브로커입니다.

  1. Producer: 메시지를 보내는 역할을 하는 애플리케이션입니다. Producer는 메시지를 RabbitMQ의 Exchange로 보냅니다.
  2. Consumer: Exchange에서 받은 메시지를 처리하는 애플리케이션입니다.
  3. Queue: 메시지가 Consumer에게 처리되기 전까지 대기하는 저장 공간입니다.
  4. Exchange: Producer가 보낸 메시지를 적절한 Queue로 전달합니다. 이때 어떤 Queue로 보낼지 결정하는 기준은 Routing Key입니다. Routing Key는 메시지를 특정 Queue로 보내기 위해 사용되는 키입니다. 예를 들어, Direct Exchange는 메시지의 Routing Key와 일치하는 Queue로만 메시지를 보냅니다. 이렇게 해서 메시지가 원하는 Queue로 정확하게 도달할 수 있게 됩니다.
  5. Binding: Binding은 Exchange와 Queue를 연결하는 것을 의미합니다. Binding을 통해 Exchange는 받은 메시지를 특정 Routing Key를 이용해 올바른 Queue로 전달합니다.
  6. Routing Key: Routing Key는 메시지를 어떤 Queue로 보낼지를 결정하는 기준입니다. Producer가 메시지를 보낼 때 이 Routing Key를 지정하며, Exchange는 이 키를 기반으로 적절한 Queue를 선택합니다.

RabbitMQ는 이러한 요소들이 함께 동작하여 메시지를 안전하고 효율적으로 전달합니다. 예를 들어, Producer가 메시지를 Exchange에 보내고, Exchange는 Routing Key를 기반으로 메시지를 올바른 Queue로 라우팅합니다. 이때 Direct, Topic, Fanout과 같은 다양한 타입의 Exchange가 존재하여 각기 다른 라우팅 방식으로 메시지를 전달할 수 있습니다.

  • Direct Exchange: 정확히 일치하는 Routing Key를 가진 메시지를 해당 Queue로 보냅니다.
  • Topic Exchange: 특정 패턴에 따라 메시지를 라우팅할 수 있어 보다 유연한 메시지 전달이 가능합니다.
  • Fanout Exchange: 메시지를 모든 연결된 Queue로 전달합니다.

이러한 구조를 통해 RabbitMQ는 다양한 메시징 시나리오를 효과적으로 지원하며, 서비스 간에 비동기적인 메시지 전달이 가능해집니다.

RabbitMQ 도커 설치 및 웹 UI 접속 방법

RabbitMQ를 Docker로 쉽게 설치하고 관리할 수 있습니다. 아래 명령어를 통해 RabbitMQ를 Docker 컨테이너로 실행할 수 있습니다:

docker run -d --name rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3-management

위 명령어는 RabbitMQ와 관리용 웹 UI를 포함한 이미지를 실행합니다.

  • -p 5672:5672: 기본 RabbitMQ 메시지 브로커 포트입니다.
  • -p 15672:15672: 관리용 웹 UI에 접근하기 위한 포트입니다.

RabbitMQ 웹 UI에 접속하려면 브라우저를 열고 http://localhost:15672로 이동하세요. 기본 사용자 이름과 비밀번호는 모두 guest입니다. 웹 UI를 통해 큐와 메시지의 상태를 모니터링하고 관리할 수 있습니다.

예제 애플리케이션 구성

이번 예제에서는 RabbitMQ 설정부터 메시지를 보내고 받는 Producer와 Consumer를 구현하는 과정을 다룹니다. RabbitMQ 설정, 메시지 전송, 메시지 수신, REST API를 통해 메시지를 발송하는 간단한 예제를 차례대로 설명하겠습니다.

1. 프로젝트 시작하기

스프링 부트 프로젝트를 시작하려면 스프링 이니셜라이저를 이용해 필요한 의존성을 추가합니다. 의존성에는 Spring WebSpring for RabbitMQ가 포함되어야 합니다. 이를 통해 스프링 부트와 RabbitMQ 간의 연결을 쉽게 설정할 수 있습니다.

2. RabbitMQ 설정 (RabbitMqConfig.java)

먼저 RabbitMQ를 설정해야 합니다. 여기서는 큐, 교환기(Exchange), 바인딩을 정의합니다. 객체를 주고받을 때는 JSON 형식으로 변환이 필요하므로 변환기를 사용해야 하지만, 이번 예제에서는 String 메시지만을 처리하기 때문에 별도의 변환기가 필요하지 않습니다.

@Configuration
public class RabbitMqConfig {
    public static final String EXCHANGE_NAME = "exampleExchange";
    public static final String QUEUE_NAME = "exampleQueue";
    public static final String ROUTING_KEY = "exampleRoutingKey";

    @Bean
    public Queue exampleQueue() {
        return new Queue(QUEUE_NAME, true); // Durable queue
    }

    @Bean
    public DirectExchange exampleExchange() {
        return new DirectExchange(EXCHANGE_NAME);
    }

    @Bean
    public Binding binding(Queue exampleQueue, DirectExchange exampleExchange) {
        return BindingBuilder.bind(exampleQueue).to(exampleExchange).with(ROUTING_KEY);
    }
}

// application.properties
# rabbitMq
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest

 

위 설정에서는 Durable한 큐를 생성하고, Direct Exchange를 사용해 특정 라우팅 키를 기반으로 큐와 바인딩합니다.

3. 메시지 전송 (MessageProvider.java)

Producer 역할을 하는 MessageProvider는 메시지를 String 형식으로 Exchange에 보냅니다.

@Service
@AllArgsConstructor
public class MessageProvider {
    private final RabbitTemplate rabbitTemplate;

    public void sendMessage(String message) {
        rabbitTemplate.convertAndSend(
                RabbitMqConfig.EXCHANGE_NAME,
                RabbitMqConfig.ROUTING_KEY,
                message
        );
        System.out.println("Message sent: " + message);
    }
}

RabbitTemplate을 이용해 메시지를 Exchange로 전송하고, 메시지가 전송되었음을 콘솔에 출력합니다.

4. 메시지 수신 (MessageConsumer.java)

Consumer 역할을 하는 MessageConsumer는 특정 큐에 도착한 메시지를 수신하고 처리합니다.

@Service
public class MessageConsumer {
    @RabbitListener(queues = RabbitMqConfig.QUEUE_NAME)
    public void receiveMessage(String message) {
        System.out.println("Message received: " + message);
    }
}

@RabbitListener 어노테이션을 사용해 큐에서 전달된 메시지를 수신하고, 콘솔에 출력합니다.

5. REST 컨트롤러 (MessageController.java)

REST API를 통해 메시지를 전송할 수 있도록 MessageController를 구현합니다.

@RestController
@AllArgsConstructor
public class MessageController {
    private final MessageProvider messageProducer;

    @PostMapping("/send")
    public String sendMessage(@RequestParam String message) {
        messageProducer.sendMessage(message);
        return "Message sent: " + message;
    }
}

/send 경로로 메시지를 전송할 수 있으며, 요청 파라미터로 메시지를 입력받습니다.

6. 테스트 방법

curl을 이용해 메시지를 전송하는 간단한 테스트를 진행할 수 있습니다.

curl -X POST http://localhost:8080/send \
-H "Content-Type: application/json" \
-d 'message=HelloRabbitMQ'

이 명령을 실행하면 메시지가 RabbitMQ로 전송되며, 서버 로그에는 다음과 같은 출력이 나타납니다:

  • MessageProvider: Message sent: HelloRabbitMQ
  • MessageConsumer: Message received: HelloRabbitMQ

7. 결론

이번 포스팅에서는 RabbitMQ와 스프링 부트를 사용해 간단한 메시징 시스템을 구축하는 방법을 알아보았습니다. RabbitMQ는 서비스 간에 비동기식 통신을 가능하게 하며, 메시지 브로커를 활용해 애플리케이션의 확장성과 유연성을 높일 수 있습니다.

RabbitMQ의 주요 구성 요소인 Producer, Consumer, Exchange, Queue, 그리고 Binding에 대해 이해하고, 이를 통해 메시지를 송수신하는 전체적인 흐름을 경험해보았습니다. 실제 운영 환경에서는 이러한 구성 요소들을 잘 활용해 더 안정적이고 확장 가능한 애플리케이션을 만들 수 있습니다.

추가적으로, RabbitMQ는 여러 유형의 Exchange(Direct, Topic, Fanout 등)를 제공하며, 상황에 따라 적절한 Exchange 타입을 선택해 더 복잡한 메시징 시나리오를 구현할 수 있습니다.

Comments