MQ를 학습하게 된 배경
기존 팀프로젝트는 DDD 설계를 이용하여 타 컨텍스트로의 요청을 할 때 webClient 혹은 SpringEvent를 발행하는 방식으로 처리를 하고 있습니다. 그러나 저희 프로젝트가 DDD로 완전히 분리하게 되며 추후 MSA를 하게 된다면 MQ 사용은 필수적인 부분이 될 것이기에 사용해보며, 또한 결제 로직과 같은 보상로직 혹은 실패시 처리가 중요한 로직 같은 경우 이벤트 손실 시 처리할 수 있는 방법이 없습니다.
따라서 재시도를 구현하거나 이벤트를 손실하는 것에 대응할 수 있는 방안을 찾자에서 시작되었습니다.
그래서 MQ란 무엇인가?
MQ의 사전적의미는 Message Queue입니다. Producer가 메세지를 Publish하고 Consumer가 이를 처리할 수 있습니다.
MQ를 왜 쓰는가?
사용이유는 다음과 같습니다.
- 비동기 처리
- Producer는 이벤트를 발행하기만 하기 때문에 그 이후를 알지 않아도 가능 ( 도메인 / 팀으로 분리되어 있을 때 생산성 향상 )
- 실패 처리 용이
- 다양한 추가 기능이 존재
MQ 비교
MQ에는 다양한 툴들이 있습니다. 가장 많이 알려진 Kafka, RabbitMQ가 있으며, Reddis도 pub/sub 구조를 통해 구현할 수 있습니다.
저희는 메세지 유실을 고려하며 생각하지만 RabbitMQ도 사용하지 않고 바로 분산서비스에서의 장점이 있다고 하는 Kafka를 쓰는 것은 저희의 환경과 맞지 않다고 생각하여 RabbitMQ를 알아보도록 하겠습니다.
RabbitMQ
RabbitMQ 사용 기업
Kafka가 많이 알려져있지만 RabbitMQ를 사용하는 국내 유명 기업도 많은 것을 알 수 있습니다. 그렇다면 어떤 이유로 RabbitMQ를 사용하는지 확인해보겠습니다.
RabbitMQ 설명
RabbitMQ는 전통적인 메세지 큐 방식을 사용합니다. 큰 흐름으로 보자면
Producer -> Exchange -> Queue -> Consumer 의 순서대로 진행됩니다.
- Producer
메시지를 보내는 쪽 (ex: 주문 서비스) - Exchange
메시지를 어떤 큐로 보낼지 라우팅하는 곳- Direct Exchange : 정확한 Routing Key 매칭
- Topic Exchange : 패턴 매칭
- Fanout Exchange : 모든 큐에 뿌림
- Headers Exchange : 헤더 값으로 라우팅
- Queue
메시지가 쌓이는 버퍼 - Consumer
큐에서 메시지를 가져와 처리하는 쪽
RabbitMQ 후기
RabbitMQ를 사용하며 생각한 부분은 설정이 굉장히 복잡하다! 입니다.
기존 SpringEvent를 사용하여 개발을 했던 저희 팀이었기 때문에 설정이라고 부를만한 부분이 없었는데 DLQ, EXCHANGE, QUEUE-BINDING 등 다양한 설정, 그리고 Dlq를 사용한다면 그 데이터를 어떻게 처리할지 등 팀적으로 정해야할 부분이 많았습니다.
또한 저희는 DDD 설계를 프로젝트에 적용했기 때문에 RabbitMQ에 사용되는 Routing Key, Exchange Name, 등 상수 혹은 Dto 클래스의 위치 등등 쉽지 않은 초기 설정 시간이 있었습니다.
그러나 이런 초기 설계 시간을 잘 보내고 나니 결과적으로는 이후 자신의 도메인 로직에만 신경 쓸 수 있게 되었습니다.
참조
https://aws.amazon.com/ko/compare/the-difference-between-rabbitmq-and-kafka/