RabbiqMQ란 무엇일까?
RabbitMQ
얼랭(Erlang)언어로 AMQP를 구현한 오픈소스 메세지 브로커.
*얼랭 : 함수형 프로그래밍 언어 (C와 비슷한 성격의 언어라고 볼 수 있겠다.)
메시지 브로커란?
Publisher(송신자)로부터 전달받은 메시지를 Subscriber(수신자)로 전달해주는 중간 역할이며
응용 소프트웨어 간에 메시지를 교환할 수 있게 한다.
즉, 소프트웨어끼리 메세지를 서로 교환할 수 있도록 중간에서 알선해주는 녀석이다.(미들웨어 라고 칭함)
AMQP
client application과 middleware broker와의 메세지를 주고 받기 위한 프로토콜
메시지 브로커가 어플리케이션(소프트웨어) 사이에서 메시지를 중개해주는 녀석이라고 했다. 양측의 어플리케이션에서 받은 메세지를 퍼나르기위한 규칙이자 방법이 AMQP인것이다.
해당 프로토콜에 따른 MQ제품중 하나가 RabbitMQ다. (다른 친구로는 그렇게 유명한 Kafka가 있다)
RabbitMQ의 동작 방식
사실상, RabbitMQ의 동작은 AMQP를 따르기 때문에 AMQP에 대한 내용을 정리한다고 보면 된다.
AMQP의 라우팅 모델은 아래와 같은 3개의 중요한 component 들로 구성된다.
- Exchange
- Queue
- Binding
AMQP는 이 3가지의 구성요소들이 서로 간에 어떻게 통신하는지를 정의한 프로토콜이라고 볼 수 있다. 전체적인 흐름은 아래의 그림과 함께 살펴보자.
Producer가 메세지를 생성하고 발송하여 Consumer에게 수신되는 그 사이의 과정이
앞서 언급한 세 가지 구성요소로 이루어져 있다.
RabbitMQ 구성요소
1) Exchange
Publisher가 보낸 메시지는 반드시 Exchange를 통해 Queue에 접근하게 된다. (큐에 직통으로 접근 불가)
exchange는 수신된 메시지를 적절한 기준에 맞는 Queue나 또다른 exchange로 라우팅한다. 즉 라우터의 기능을 수행하는데, 간단하게 말해서 길잡이 역할을 해준다는 것이다.
방금 언급한 ‘적절한 기준’을 exchange type이라고 한다.
exchange type은 메시지를 어떤 방법으로 라우팅 시킬지를 결정하며, AMQP에서는 해당 방법을 표준화하여 Standard Exchange Type을 제시한다. (표준화 된 방법을 기준으로 exchage가 메시지를 라우팅 하도록!)
2) Binding
Exchange와 큐와의 관계를 정의한 일종의 라우팅 테이블이다.
Exchange와 Queue를 연결짓는 행위라고 볼 수 있는데, Exchange는 Publisher로부터 수신한 메시지를 Binding에 따라 적절한 Queue나 또다른 Exchange로 라우팅하게 된다.
Binding과 Exchange Type의 차이점?
두 요소를 정리하다보면.. 매우 유사하게 느껴진다. exchange type은 메시지를 어떤 방법으로 라우팅 시킬지를 결정하는 것이다. 즉 전달받은 메세지를 분리하는 ‘방법’이 되고, binding을 이러한 방법을 이용해 실제로 어떤 메시지를 어떤 큐에 보낼지를 결정한다.
이메일정보가 들어오면 특정 큐로 보내는 broker가 있다고 가정해보자.
이메일 도메인 정보(@뒤에 오는 주소)를 보고 큐를 결정하겠다. → exchange type
naver는 1번큐, google은 2번큐, daum은 3번큐로 보내겠다 → binding
3) Queue
Producer들이 발송한 메세지들이 Consumer가 소비하기 전까지 보관되는 장소
메모리나 디스크에 메시지를 저장하고, 그것을 consumer에게 전달하는 역할을 한다.
큐는 Binding을 통해 Exchange에 bind(연결)된다.
Standard Exchange Type
Exchange Type은 메시지를 어떤 원칙이나 방법으로 라우팅할지를 결정하는 일종의 알고리즘이다.
AMQP는 4개의 Standard Exchange Type을 규정하여 표준화 된 방법으로 exchage가 메시지를 라우팅 하도록 설계했다.
Routing Key
Publisher에서 송신한 메시지 헤더에 포함되는 것으로 일종의 가상 주소라고 보면 된다.
Exchange가 어떤 큐로 메시지를 라우팅할지 결정하는 도구 중 하나다.
Direct Exchange
메시지의 라우팅 키를 큐에 1:N으로 매칭시키는 방법이다.
일반적으로 큐의 이름과 라우팅 키를 동일하게 작성하여 바인딩한다.
Topic Exchange
와일드카드를 이용해서 메시지를 큐에 매칭시키는 방법이다.
"*"는 하나의 단어, "#"은 0개 이상의 단어를 의미한다. “.” (dot)로 구별되는 단어의 리스트를 가져야한다.
(ex. “abc.apple.one”, “aaa.banana.two”)
Fanout Exchange
모든 메시지를 모든 큐로 라우팅하는 유형이다. 일종의 브로드캐스트 개념
Headers Exchange
이전 3개의 경우는 ‘라우팅 키’를 사용하여 결정했다면, 해당 Exchange Type은 key-value로 정의된 헤더에 의해 라우팅을 결정한다.
큐를 바인딩할 때 x-match라는 특정 argument를 기준으로 어떻게 바인딩할지를 결정한다.
x-match가 all → 바인딩 조건을 모두 충족시켜야 한다(AND), x-match가 any → 하나만 충족시키면 된다(OR)
각 Exchange Type을 표로 정리하면 다음과 같다.
타입 | 설명 | 특징 |
Direct | Routing key가 정확히 일치하는 Queue에 메세지 전송 | Unicast |
Topic | Routing key 패턴이 일치하는 Queue에 메세지 전송 | Multicast |
Headers | [key:value]로 이루어진 header 값을 기준으로 일치하는 Queue에 메세지 전송 | Multicast |
Fanout | 해당 Exchange에 등록된 모든 Queue에 메세지 전송 | Broadcast |
** 보너스!
Prefetch Count
하나의 Queue에 여러 Consumer가 존재할 경우, Queue는 기본적으로 Round-Robin 방식으로 메세지를 분배한다.
(라운드-로빈 : 순서대로 한번씩 돌아가는 방식)
그런데, Consumer가 2개인 상황에서 홀수번째 메세지는 처리 시간이 짧고, 짝수번째 메세지는 처리 시간이 매우 긴 경우, 계속해서 하나의 Consumer만 일을 하게 되는 상황이 발생할 수 있다!
이를 예방하기 위해, prefetch count를 1로 설정해 두면, 하나의 메세지가 처리되기 전(Ack를 보내기 전)에는 새로운 메세지를 받지 않게 되므로, 작업을 분산시켜 좀 더 효율적으로 운영할 수 있다.
[Reference]