얼마 전에 관리하는 애플리케이션에서 RabbitMQ와 Connection을 유지하고 관리하는 로직이 잘못되어 MQ의 Connection Port를 과도하게 점유하는 이슈와 부딪히게 되었다.
이러한 현상은 의도한 것이 아니었고 Connection 관리는 RabbitMQ 동작 흐름과는 큰 관계가 있는 것은 아니었지만 기본적인 해상도를 높이기 위해 복습 차원에서 RabbitMQ에 대한 기본 지식을 정리하려고 한다.
오늘의 주제는 RabbitMQ에서 메시지를 라우팅 하기 위한 논리적인 개념인 Exchange이다. 이전에 RabbitMQ에 대한 소개를 간단하게 짚고 가려고 한다.
RabbitMQ란?
RabbitMQ는 메시지 브로커으로, 애플리케이션 간에 비동기 메시지를 전달해 주는 역할을 한다. 오픈 소스이며 신뢰성과 확장성이 높아 다양한 언어와 플랫폼에서 사용되고 있다. 이를 통해서 여러 서비스 간의 통신을 간소화하고 데이터 처리를 분산시킬 수 있다.
RabbitMQ는 웬만해서 대규모 서비스에서도 잘 버티고 단단해서 믿고 쓰기 좋은 것 같다.
RabbitMQ는 왜 사용하는 것일까?
RabbitMQ의 대표적인 장점은 아래와 같다.
- 비동기 처리: 하나의 작업을 요청하고 바로 응답받을 수 있어, 여러 프로세스가 동시에 작업을 수행할 수 있다.
- 신뢰성: 메시지를 잃지 않도록 보장하는 기능을 제공하므로 데이터를 안전하게 전달한다.
- 확장성: 많은 요청이 발생해도 클러스터링 기능으로 확장이 가능하다.
AMQP 프로토콜이란?
RabbitMQ의 주제에서는 AMQP 프로토콜에 대한 내용을 뺄 수 없을 것 같다.
AMQP (Advanced Message Queuing Protocol)는 RabbitMQ에서 사용하는 표준 프로토콜이다. 이 프로토콜은 메시지가 전송되는 방식을 표준화하여 다양한 애플리케이션이 통신할 수 있도록 한다. 이를 통해 RabbitMQ는 메시지 전달 실패 시 재전송 기능과 같은 안전장치를 제공할 수 있다.
RabbitMQ의 메시지 흐름
RabbitMQ에서 메시지가 전달되는 과정은 크게 Producer, Exchange, Queue, Consumer 네 가지 요소가 있다.
이 글에서는 Exchange를 제외한 나머지는 소개하지 않겠다.
Exchange란?
본격 Exchange에 대해 소개를 하겠다. RabbitMQ에 대한 소개가 좀 길어져서 비교적 내용이 없을 것 같다...
Exchange는 메시지가 어떤 Queue로 가야 하는지 결정하는 핵심 요소로 동작한다. Exchange는 각 메시지를 특정 기준에 따라 분류하여 필요한 Queue에 전달하며, Producer가 메시지를 직접 Queue에 넣지 않고 Exchange에 전달하는 방식으로 유연한 라우팅을 가능하게 한다.
Exchange는 어떻게 존재하는가?
Exchange는 논리적 개념이다. 물리적으로는 Queue만이 메시지를 저장하는 실체를 가지고 있으며, Exchange는 단순히 메시지를 라우팅 하는 역할만 수행한다. 즉, 메시지를 저장하거나 보관하지 않는다.
Exchange는 메시지가 특정 조건에 따라 다양한 Queue로 전달될 수 있도록 라우팅 규칙을 정하는 논리적 엔티티로 이해하면 된다. 이를 통해 RabbitMQ는 Producer와 Consumer 간의 느슨한 결합을 유지하면서도 다양한 라우팅 옵션을 지원할 수 있게 한다.
따라서 Exchange 자체가 물리적 자원을 소비하거나 메시지를 보관하지 않으며, 오로지 메시지가 올바른 Queue로 전달되도록 하는 라우팅 로직만 담당한다.
Exchange Type의 종류
바로 위에서 Exchange는 메시지가 특정 조건에 따라 다양한 Queue로 전달될 수 있도록 라우팅 규칙을 정의한다고 하였다. 이 규칙들이 Exchange Type이다. Exchange Type은 네 가지가 있다.
1. Direct Exchange
- 지정된 라우팅 키와 정확히 일치하는 Queue로 메시지를 전달한다.
- Direct Exchange를 통해서 목적에 맞게 설계된 Queue에 각각 매칭되는 라우팅 키들을 바인딩하면, 특정 라우팅 키의 메시지는 해당 라우팅 키로 바인딩된 Queue에만 메시지를 전송한다.
- 핵심은 "라우팅 키와 정확히 일치하는 Queue로"이다.
2. Fanout Exchange
- 라우팅 키와 상관없이 모든 바인딩된 Queue에 메시지를 복사하여 전달한다.
- 이는 라우팅 키를 무시하고 메시지를 받아 연결된 모든 Queue로 전송하기 때문에, 동일한 메시지를 여러 Queue에 동시에 보내야 하는 상황에 적합하다.
- 핵심은 "라우팅 키와 상관없이 모든 바인딩된 Queue로"이다.
3. Topic Exchange
- 특정 패턴에 맞는 라우팅 키를 가진 Queue로 메시지를 전달하는 방식이다.
- 라우팅 키에 "." 구분자와 와일드카드 (*, #)를 사용할 수 있어, 복잡한 라우팅이 가능하게 하여 세분화된 라우팅이 필요한 경우 유용하다.
- 핵심은 "특정 패턴에 맞는 라우팅 키를 가진 Queue로"이다.
4. Headers Exchange
- 라우팅 키 대신 헤더에 정의된 속성을 기반으로 메시지를 라우팅 한다.
- 이 방시은 라우팅 키 대신 메시지의 헤더 정보를 활용하므로, 여러 조건을 복합적으로 설정하여 특정 조건을 만족하는 Queue로만 메시지를 보낼 수 있다. 특히, 라우팅 키보다 더 복잡한 조건이나 다양한 필터링 기준이 필요할 때 유용하다.
- 핵심은 "메시지를 헤더에 포함된 속성값을 기준으로 메시지를 라우팅"이다.
각 Exchange Type을 선택 시 주의사항
1. Direct Exchange
- Direct Exchange에 대한 공식적인 설명에는 라우팅 키의 대소문자 구분에 대한 언급은 없지만 대소문자를 구분한다고 한다. 또한 라우팅 키의 오타도 주의해야 한다.
- 단일 라우팅 키로 여러 Queue에 바인딩하면, 메시지를 해당 라우팅 키와 일치하는 모든 Queue에 복제하여 전달한다. 이는 메시지 중복처리, 성능 저하 등이 의도한 방식을 벗어나지 않도록 주의해야 한다.
2. Fanout Exchange
- Fanout Exchange는 브로드 캐스트로 모든 바인딩된 Queue로 메시지를 전달하기 때문에 네트워크 자원과 성능 저하를 고려해야 한다.
- 특정 조건에 따라 메시지를 필터링하거나 선택적으로 전달하지 못한다.
3. Topic Exchange
- 헤더 크기에 따라 성능 저하가 될 수 있기 때문에 헤더 필드를 간단하고 명확하게 유지해야 한다.
RabbitMQ의 기본 적인 컨셉과 중요 개념 중 하나인 Exchange와 그의 type들에 대해 작성하였다.
RabbitMQ의 사용법은 정말 간단하고 자체 어드민 페이지도 제공하고 있어서 UI를 통해 설정도 어렵지 않게 할 수 있다. 그러나 사용하기 쉬운 것과 별개로 모르고 써도 된다는 생각을 가지지 않아야 된다.