13.2 Message Queue 기초와 RabbitMQ 연동
**메시지 큐(Message Queue)**는 서비스 간 비동기 통신을 가능하게 하는 미들웨어입니다. A 서비스가 B 서비스의 응답을 기다리지 않고 메시지를 큐에 던지며 B가 나중에 자신의 페이스로 소화하는 구조로, 서비스 간 결합도를 극적으로 낮춰줍니다.
1. AMQP와 Exchange-Queue 라우팅 개념
RabbitMQ는 AMQP 프로토콜 위에서 동작합니다. 메시지는 항상 Producer → Exchange → Binding → Queue → Consumer 순서로 흐릅니다.
- Exchange 유형:
Direct: 라우팅 키가 정확히 일치하는 큐에만 전달 (1:1)Topic: 와일드카드(*,#) 패턴 매칭으로 여러 큐에 전달Fanout: 바인딩된 모든 큐에 브로드캐스트 (1:N)
2. Spring AMQP 빠른 설정
implementation 'org.springframework.boot:spring-boot-starter-amqp'
@Configuration
public class RabbitMqConfig {
public static final String QUEUE_NAME = "order.queue";
public static final String EXCHANGE_NAME = "order.exchange";
public static final String ROUTING_KEY = "order.created";
@Bean
public Queue orderQueue() {
// durable = true: RabbitMQ 재시작 후에도 큐가 살아남음
return new Queue(QUEUE_NAME, true);
}
@Bean
public DirectExchange orderExchange() {
return new DirectExchange(EXCHANGE_NAME);
}
@Bean
public Binding binding(Queue orderQueue, DirectExchange orderExchange) {
return BindingBuilder.bind(orderQueue).to(orderExchange).with(ROUTING_KEY);
}
@Bean
public MessageConverter jsonMessageConverter() {
return new Jackson2JsonMessageConverter(); // 자바 객체를 JSON으로 직렬화하여 전송
}
}
3. 메시지 발행(Producer)과 소비(Consumer)
// [Producer] 메시지 발행
@Service
@RequiredArgsConstructor
public class OrderProducer {
private final RabbitTemplate rabbitTemplate;
public void sendOrderCreatedEvent(OrderCreatedEvent event) {
rabbitTemplate.convertAndSend(
RabbitMqConfig.EXCHANGE_NAME,
RabbitMqConfig.ROUTING_KEY,
event
);
log.info("주문 이벤트 발행 완료: {}", event.getOrderId());
}
}
// [Consumer] 큐에서 메시지 소비
@Service
public class OrderConsumer {
@RabbitListener(queues = RabbitMqConfig.QUEUE_NAME)
public void handleOrderCreated(OrderCreatedEvent event) {
log.info("주문 이벤트 수신: {}", event.getOrderId());
// 이메일 발송, 재고 차감 등 비동기 후처리 수행
}
}
경고
@RabbitListener 내부에서 예외가 발생하면, RabbitMQ는 기본적으로 메시지를 큐로 다시 되돌립니다(requeue). 무한 재시도 루프를 막기 위해 Dead Letter Queue(DLQ) 설정이나 재시도 횟수 제한(RetryInterceptor)을 반드시 함께 구성해야 합니다.