RabbitMQ보다 중요한 AMQP 알아보기

머랭·2026년 1월 10일
post-thumbnail

0. 서론

"RabbitMQ를 사용해 보셨나요? 그렇다면 AMQP가 무엇인지 아시나요?"

글의 목적

안녕하세요, 백엔드 개발자(지망생) 머랭입니다.
많은 개발자가 RabbitMQ를 사용하지만, 그 근간이 되는 AMQP의 깊은 곳까지는 들여다보지 못하곤 합니다.

AMQP는 크게 0-9-1 버전과 1.0 버전으로 나뉩니다. 언뜻 보면 1.0이 0-9-1의 상위 호환 버전처럼 느껴지지만, 실제로는 지향점이 완전히 다른 프로토콜입니다.

  • AMQP 0-9-1은 Exchange, Queue, Binding 등 브로커 내부의 동작 모델을 구체적으로 명시했습니다.
  • AMQP 1.0은 브로커 내부 구현을 각 벤더에게 맡기고, 전송 규약에 집중하는 추상적인 접근을 택했습니다.

RabbitMQ는 현대 개발 시장에서 가장 유명한 AMQP 0-9-1 구현체입니다.

RabbitMQ 4.0이 출시되며 AMQP 1.0을 플러그인 형태로 지원하기 시작했지만, 여전히 전 세계 수많은 메시징 시스템은 AMQP 0-9-1 위에서 동작하고 있습니다.

이번 포스팅에서는 현대 개발 시장에서 활발하게 사용되는 AMQP 0-9-1 프로토콜의 공식 문서와 논문을 분석하며 얻은 본질적인 동작 원리를 공유하고자 합니다.

대상 독자

  1. RabbitMQ 등 AMQP 기반 브로커에 대한 기본 흐름을 알고 있는 개발자
    • 그 중에서도, 내부 동작 방식에 대해 더 깊은 호기심을 가진 개발자.
  2. "왜"를 찾는 멋진 개발자
    • AMQP가 왜 그렇게 설계되었는지 그 논리와 내부 동작이 궁금한 개발자.

단순히 "어떤 라이브러리를 써서 어떻게 보낸다"는 방법론을 넘어, AMQP 0-9-1 공식 문서를 탐구하며 얻은 지식을 바탕으로 "AMQP는 왜 그렇게 동작하는지"에 대한 본질적인 답을 찾아보고자 합니다.

글을 통해 얻어갈 수 있는 것들

라이브러리 메서드 하나로 메시지를 보낼 수 있는 편리한 시대에, 수백 페이지의 명세서를 읽으며 내부 구조를 탐구하는 이유는 명확합니다.
도구를 사용하는 것을 넘어, 기술의 본질을 이해하고 통제하는 힘을 가질 수 있습니다.

  1. AMQP에 대한 깊은 이해
    • Exchange, Queue, Binding이 맺는 유기적인 관계와 라우팅 논리를 명확히 이해할 수 있습니다.
  2. 물리적 실체에 대한 이해
    • 데이터(메시지)가 네트워크 위에서 어떻게 Frame 단위로 쪼개지고 조립되는지 파악할 수 있습니다.
  3. 코더에서 시스템 설계 능력을 갖춘 개발자로의 진화
    • "~ 하니까 되던데?" 와 같은 비논리적인 사고방식에서, 근본을 이해하고 시스템을 설계하는 개발자로 나아갈 수 있습니다.

1. AMQP의 탄생 배경

AMQP는 월스트리트의 투자 은행 JPMorgan에서 시작되었습니다.

기존의 상용 메시징 미들웨어는 메시지 형식이 제각각이었고, 특정 벤더에 종속적이라는 단점이 있었습니다.

ex) IBM의 메시징 미들웨어가 전송한 메시지를 Microsoft의 Consumer가 처리할 수 없었습니다.
이를 가능하게 하려면 메시지 형식 변환 브릿지(어댑터)를 개발해야 했습니다.

AMQP 개발자들은 메시징 기술이 TCP/IP처럼 누구나 사용할 수 있는 공용어가 되기를 원했습니다.
특정 벤더의 기술이나 프로토콜에 얽매이지 않고, 이기종 시스템 간에도 메시지를 신뢰성 있게 교환할 수 있는 개방형 표준을 만드는 것이 AMQP의 목표였습니다.


2. 철학

Broker 중심 아키텍처

Broker는 복잡한 메시지 라우팅, Queue 관리를 비롯해 메시지 전송의 모든 책임을 집니다.

Consumer가 메시지를 잘 받았는지 확인될 때까지 Broker는 메시지를 보관하고 관리하며, 처리가 완료되면 Queue에서 메시지를 제거합니다.

최소 한 번 전달(At-least-once)

메시지를 최소한 한 번 전달합니다.

메시지 유실을 방지하지만, 두 번 전달되는 것은 막을 수 없어 멱등한 비즈니스 로직을 작성해야 합니다.

Pub-Sub 기반 Push 전송

Consumer가 데이터를 가져오기 위해 대기하거나 주기적으로 확인할 필요가 없습니다.

Broker는 새로운 메시지가 Queue에 도착하면 연결된 Consumer에게 즉시 전달합니다.

이 과정에서, prefetch 메커니즘을 통해 Consumer가 처리 가능한 메시지 양을 Broker에 알림으로써, 무분별한 Push로 인한 시스템 마비를 방지합니다


3. 핵심 구성 요소 - 공통

3.1 Frame

설명

Frame은 AMQP 통신에서 네트워크를 타고 흐르는 데이터의 최소 단위입니다.

TCP는 데이터 경계가 없는 스트림 방식이기 때문에, 어디서부터 어디까지가 하나의 데이터 단위인지 구분하기 위해 모든 데이터를 Frame으로 포장해 주고받습니다.

Frame은 네 가지로 분류됩니다.

  • 명령을 주고받기 위한 Method Frame
  • 메시지의 메타데이터를 주고받기 위한 Content Header Frame
  • 메시지의 실제 데이터를 주고받기 위한 Content Body Frame
  • Peer 간 하트비트를 주고받기 위한 Heartbeat Frame

구조

  • type: Frame의 유형을 나타냅니다.
    • 1: Method Frame
    • 2: Content Header Frame
    • 3: Content Body Frame
    • 4: Heartbeat Frame
  • channel: 해당 Frame이 속한 Channel 번호입니다.
  • size: payload 영역의 총 바이트 수입니다.
  • payload: 실제 데이터가 담기는 공간입니다.
  • frame-end: Frame의 끝을 알리는 특수한 값입니다.

3.2 Method(Method Frame)

설명

AMQP는 기능들을 Class로 묶고, 그 안의 동작을 Method로 정의합니다.

Method Frame은 Peer간 명령을 주고받기 위해 사용되는 Frame입니다.

“test-queue라는 이름의 큐를 생성해라” 혹은 “A Exchange를 제거해라”와 같은 명령 데이터를 주고받기 위해 사용됩니다.

개인적으로 CPU instruction set architecture와 비슷한 개념이라고 느꼈습니다.

구조

  • class-id: Method가 저장되어있는 Class의 ID입니다.
  • method-id: 해당 Class의 명령 번호입니다.
    • 예: Reject(거절) = 90입니다.
  • arguments: 명령을 수행하는 데에 필요한 매개변수들입니다.

3.3 Message

설명

A message is the atomic unit of processing of the middleware routing and queuing system. Messages carry a content, which consists of a content header, holding a set of properties, and a content body, holding an opaque block of binary data.

메시지는 미들웨어 라우팅 및 대기열 시스템의 처리를 위한 원자 단위입니다. 메시지는 콘텐츠 헤더, 속성 세트, 불투명한 이진 데이터 블록을 포함하는 콘텐츠 본문으로 구성된 콘텐츠를 전달합니다.
AMQP 0-9-1 공식 문서 중..

메시지는 AMQP 시스템에서 데이터 이동의 최소 단위입니다.
논리적인 최소 단위이며, 실제로는 Frame이 데이터 이동의 최소 단위입니다.

  • 영속성(Persistence): 영속화되어 디스크에 저장될 수 있습니다.
  • 우선순위(Priority): 우선순위를 가질 수 있습니다. 우선순위가 높은 메시지가 먼저 처리되거나, 우선순위가 낮은 메시지가 우선적으로 폐기됩니다.
  • 불투명성(Opaque)과 불변성(Immutable): Broker는 메시지의 본문을 확인하거나 수정해선 안됩니다.

구조

메시지는 Content HeaderContent Body라는 두 계층으로 설계되었습니다.

메시지를 전달하는 주체는 Content Header 영역의 데이터만 사용해 메시지를 전달합니다.

Content Header: 메타데이터 영역으로, 메시지의 속성(Properties)이 담겨 있습니다.

  • body-size: Content Body 영역의 크기 값입니다.
  • delivery-mode: 영속화 옵션으로, 메시지를 메모리에만 저장할지 디스크에도 저장할지 설정할 수 있습니다.
  • priority: 우선순위(0~9)로, 우선순위가 높은 메시지는 먼저 처리됩니다.
  • reply-to: 응답을 받을 Queue의 이름을 명시하여 Request-Response 패턴을 구현할 수 있습니다.

Content Body: 실제로 애플리케이션이 전달하고자 하는 비즈니스 데이터가 담겨 있습니다.

  • 바이너리 형태로 저장되며, Producer와 Consumer를 제외한 모든 Peer는 메시지의 본문을 확인하거나 수정해선 안됩니다.
    • Zero-Copy를 통해 메시지 처리량을 높이기 위함입니다.

3.4 Connection & Channel

설명

AMQP에서 통신은 물리적 연결인 Connection과 논리적 통로인 Channel의 이중 구조로 이루어집니다.

Channel은 메시지를 Frame 단위로 분해하여 전송하는 실질적인 데이터 스트리밍의 주체입니다.

  • Connection: Peer 간 맺는 물리적 TCP 연결로, Peer들은 Connection을 통해 여러 Frame을 전송합니다.
    • Connection으로 전송되는 메시지는 여러 개의 Frame으로 나뉘어집니다. (메시지 분할은 Channel이 수행)

    • 덕분에 멀티스레드 환경에서 여러 메시지를 동시에 전송할 수 있습니다.

    • 단일 TCP 연결은 대역폭 한계가 존재하므로, 여러 개의 Connection을 생성해 Connection 풀을 구성할 수 있습니다.

      만약 메시지가 Frame 단위로 나뉘어지지 않는다면?
      한 스레드가 Connection을 독점하고 자신이 보낼 모든 메시지를 보낸 후 Connection을 반납합니다.
      그 과정에서 다른 스레드는 Blocking됩니다.
      결과적으로, 처리량이 낮아집니다

  • Channel: Connection 내부에 생성되는 논리적인 가상 통로로, 메시지를 Frame으로 쪼개 Connection으로 전송하는 동작을 추상화해 제공하는 인터페이스입니다.
    • Channel을 여는 행위는 Peer에게 지금부터 이 Channel 번호로 대화하자는 합의를 보내는 과정입니다. TCP 연결을 맺는 것과는 다릅니다.
    • Peer에게 Channel.Open Frame을 전송해 Channel 생성을 알립니다.
    • Peer는 Channel.Open-Ok 메서드 Frame을 응답해 Channel 생성을 합의합니다.
    • Channel을 여는 행위는 2번의 네트워크 비용을 요구하기 때문에, 여러 Channel을 생성해 Channel 풀을 구성할 수 있습니다.

3.5 Routing Key

설명

Routing Key는 Producer가 메시지를 발행할 때, 메시지와 함께 전송하는 문자열입니다.

Exchange는 Routing Key를 사용해 메시지를 어떤 Queue로 전달할지 결정합니다.
Producer는 메시지가 정확히 어떤 Queue로 전달되어야 하는지에 관심가지지 않고 Routing Key만 Exchange에 전달합니다.
덕분에 Broker는 단순한 1:1 전달을 넘어 하나의 메시지를 여러 Queue에 전달하거나 특정 조건에 맞는 곳으로만 보내는 복잡한 라우팅을 로직을 수행할 수 있습니다.
대소문자를 구분하므로, 설계 시 참고해야 합니다.

Point-To-Point 방식을 사용하려면 Routing Key를 Queue의 이름으로 설정합니다.
Pub-Sub 방식을 사용하려면 데이터의 성격을 나타내는 계층적 값을 사용합니다.

예: order.new, payment.success

구조

255 octet 크기의 문자열 형식으로 이루어집니다.

octet: 8비트 크기의 데이터 단위로, 과거 1 바이트가 8비트이지 않은 경우가 있어 생긴 단위입니다.


4. 핵심 구성 요소 - Producer

설명

Producer는 메시지를 생성하고 Broker를 향해 발행하는 클라이언트 애플리케이션입니다.
Producer는 Queue에 메시지를 직접 발행하지 않고, 메시지와 Routing Key를 Exchange에게 전송합니다.
메시지를 Queue에 전달하는 과정은 Broker에서 이루어집니다.

높은 처리량을 위해 Producer → Broker 간 메시지 수신응답(ACK/NACK)은 이루어지지 않습니다.

RabbitMQ는 확장 기능으로 이 기능을 제공합니다. 신뢰성이 중요한 경우 사용할 수 있습니다.

동작

  1. 메시지 전송 시작 Frame 전송
    • 메시지를 여러 Frame으로 쪼갠 후 모든 Frame 헤더에 Channel 번호를 기입합니다.
    • Basic.Publish Method Frame을 생성해 Connection으로 전송합니다.
      • Basic.Publish Method Frame은 메시지 생산 시작을 위한 Method Frame 입니다.
      • Basic.Publish Method Frame에는 다음 Arguments가 포함됩니다.
      • Exchange 이름
      • Routing Key
      • Mandatory(필수 전달) 플래그
        • 해당 Routing Key와 매칭되는 Queue가 존재하지 않을 때 Basic.Return Method Frame을 통해 Producer에게 메시지를 반환합니다.
        • Basic.Return Method Frame은 메시지 라우팅 실패를 알리기 위한 Method Frame입니다.
      • Immediate(즉시 전달) 플래그
        • Queue에서 즉시 메시지를 소비할 수 있는 Consumer가 존재하지 않을 때 Basic.Return Method Frame을 통해 Producer에게 메시지를 반환합니다.

          RabbitMQ 3.0 이상에서는 다중 Consumer 에 대한 메시지 소비 체크 오버헤드로 인해 Immediate 플래그를 지원하지 않습니다.

    • Basic.Publish Method Frame을 전달받은 Broker는 이제 해당 Frame을 보낸 Channel에서 메시지 Frame을 보낼 것임을 인지합니다.
  2. 메시지 Frame 전송
    • Broker에게 메시지의 Content Header Frame을 전송합니다.
      • Broker는 Content Header Frame의 body size를 확인합니다.
    • Broker에게 Content Body Frame들을 전송합니다.
      • Broker는 전달받는 Content Body Frame들의 데이터 합계가 body size와 일치할 때까지 계속해서 Content Body Frame을 수신합니다.

5. 핵심 구성 요소 - Broker

AMQP의 핵심인 Broker는 메시지의 수신, 라우팅, 보관 및 전달을 총괄하는 시스템입니다.

5.1 Exchange

설명

Exchange는 Producer로부터 수신한 메시지를 하나 이상의 Queue 혹은 Exchange로 전달하기 위한 라우팅 엔진입니다.
라우팅 규칙에 따라 하나의 메시지를 여러 Queue 혹은 Exchange에 동시에 전달할 수 있습니다.
메시지의 Content Body에는 관여하지 않으며, 수신한 데이터를 변경 없이 그대로 전달합니다.

구조

가장 중요한 속성 세 가지에 대해 설명하겠습니다.

  • name: Exchange를 식별하기 위한 고유한 이름입니다.
  • type: 메시지 라우팅 알고리즘입니다.
    • Direct Exchange(Unicast): Routing Key와 Binding Key가 정확히 일치하는 바인딩의 Queue 혹은 Exchange로 전달합니다.
    • Topic Exchange(Multicast): Binding Key 패턴(예: order.*)이 Routing Key(예: order.new)에 매칭되는 바인딩의 Queue 혹은 Exchange로 메시지를 전달합니다.
    • Headers Exchange(Multicast): Routing Key와 Binding Key 대신 메시지의 Content Header 내 headers 테이블의 속성값을 기준으로 전달합니다.
    • Fanout Exchange(Broadcast): Routing Key를 무시하고 해당 Exchange에 바인딩된 모든 Queue 혹은 Exchange로 메시지를 전달하는 브로드캐스트 방식을 수행합니다.
  • durability: Broker 재시작 시 Exchange 보존 여부입니다
    • true: 비휘발성 Exchange
      • Exchange 정보를 디스크에 저장합니다.
      • Broker 재시작 후에도 비휘발성 Exchange들은 유지됩니다.
    • false: 휘발성 Exchange
      • Broker가 종료되면 휘발성 Exchange들은 사라집니다.
      • 재시작 후 다시 사용하려면 새로 생성해야 합니다.

동작

  1. 서버의 메시지 수신
    • Channel을 통해 들어온 Basic.Publish Method Frame을 읽어 Exchange Name과 Routing Key를 확인합니다.
    • 이후 도착한 Content Header와 Content Body Frame을 조립하여 완성된 메시지 객체를 생성합니다.
    • 최종적으로 Exchange는 메시지를 수신하게 됩니다.
  2. Binding 테이블을 통한 메시지 라우팅
    • 각 Exchange는 Binding Table을 참조하며, 이 Binding Table에는 Binding 목록이 저장되어 있습니다.
      • Binding Table은 Broker의 메타데이터 저장소에 존재합니다.
    • Binding Table을 통해 연결(바인딩)할 수 있는 Queue를 찾아 메시지를 전달합니다.

5.1.1 Direct Exchange

Routing Key와 Binding Key가 정확히 일치하는 바인딩의 Queue 혹은 Exchange로 메시지를 전달합니다.

Routing Key: order.new, Binding Key: order.new

  • Binding Key가 정확히 일치하기 때문에 메시지가 전달됩니다.

Routing Key: order.new, Binding Key: order.cancel

  • Binding Key가 일치하지 않기 때문에 메시지가 전달되지 않습니다.

5.1.2 Fanout Exchange

Binding Key, arguments를 사용하지 않고, 모든 Binding의 목적지로 메시지를 전달합니다(Broadcast).


5.1.3 Topic Exchange

Binding Key 패턴이 Routing Key와 매칭되는 Binding의 목적지에만 메시지를 전달합니다.

Routing Key: order.new, Binding Key: order.*

  • Binding Key 패턴이 Routing Key와 매칭되기 때문에 메시지가 전달됩니다.

Routing Key: payment.new, Binding Key: order.*

  • Binding Key 패턴이 Routing Key와 매칭되지 않기 때문에 메시지가 전달되지 않습니다.

5.1.4 Headers Exchange

메시지 Content Headers 내의 headers 테이블 내 속성과 arguments 내의 속성을 비교해 메시지를 전달할 지 결정합니다.

headers 테이블: { ”membership”: “VIP”, “foodType”: “PIZZA” }
arguments: { ”membership”: “VIP”, “foodType”: “PIZZA”, "x-match": "all” }

  • headers 테이블 내 속성과 arguments의 모든(all 이기 때문) 속성이 일치하기 때문에 메시지가 전달됩니다.

headers 테이블: { “foodType”: “PIZZA” }
arguments: { ”membership”: “VIP”, “foodType”: “PIZZA”, "x-match": "any” }

  • headers 테이블 내 속성과 arguments의 하나 이상의(any 이기 때문) 속성이 일치하기 때문에 메시지가 전달됩니다.

headers 테이블: { ”membership”: “VIP” }
arguments: { ”membership”: “VIP”, “foodType”: “PIZZA”, "x-match": "all” }

  • headers 테이블 내 속성과 arguments의 모든(all 이기 때문) 속성이 일치하지 않기 때문에 메시지가 전달되지 않습니다.

5.2 Binding

설명

Binding은 Exchange가 수신한 메시지를 다음 목적지로 전달하기 위한 논리적인 연결 규칙입니다.
단순히 Exchange-Queue 형태로 연결하는 것을 넘어, Exchange-Exchange 형태로 메시지 라우팅 경로를 체이닝할 수 있습니다.

구조

  • source: 메시지를 보내는 출발지 Exchange의 이름입니다.
  • destination: 메시지를 받는 목적지의 이름입니다.
  • destination type: 목적지의 타입입니다.
    • 목적지는 Queue혹은 Exchange입니다.
  • binding key: 라우팅 시 Routing Key와 대조할 기준 패턴 문자열입니다.
    • 예: order.new, order.*
  • arguments: Headers: Map을 기반으로 하는 필터 조건으로, Headers Exchange에서 사용합니다.
    • arguments 내의 x-match 속성은 사전 정의 속성으로, allany 값을 가질 수 있습니다.
      • all: 메시지 Content Headers 내의 headers 테이블 내 속성이 전부 일치해야 메시지를 전달합니다.
      • any: 메시지 Content Headers 내의 headers 테이블 내 속성이 하나라도 일치하면 메시지를 전달합니다.
      • 예: { ”membership”: “VIP”, “foodType”: “PIZZA”, "x-match": "all” }

동작

  1. 각 Exchange는 Binding Table을 참조하며, 이 Binding Table에는 Binding 목록이 저장되어 있습니다.
  2. Exchange는 메시지를 전달받으면, Binding Table을 통해 연결(바인딩)할 수 있는 Queue를 찾아 메시지를 전달합니다.
  3. Binding을 어떻게 사용하는지는 Exchange 타입 별로 나뉩니다.

5.3 Queue(Message Queue)

설명

Queue는 메시지가 최송 소비되기 전까지 보관되는 FIFO 버퍼입니다.
기본적으로 FIFO 구조이지만, 다중 소비자 환경이나 메시지 우선순위(Priority) 사용 시 엄격한 순서가 보장되지 않을 수 있습니다.

  • 이를 Weak-FIFO라 부릅니다.

하나의 Queue에는 동일한 역할을 하는 여러 Consumer가 연결될 수 있습니다.

AMQP 모델에서 Queue는 단순한 저장소가 아니라 영리한 객체(Reasonably clever object)로 설계되었습니다.
메시지가 도착하면, Queue는 연결된 Consumer에게 즉시 메시지를 전달하려고 시도합니다.
다중 Consumer 존재 시, 일반적으로 라운드 로빈(Round-Robin) 방식으로 메시지를 분배합니다.

구조

  • name: Queue를 식별하기 위한 고유한 이름입니다.
  • durable: Broker 재시작 시 Queue 보존 여부입니다
    • true: 비휘발성 Queue
      • Queue 정보를 디스크에 저장합니다.
      • Broker 재시작 후에도 비휘발성 Queue들은 유지됩니다.
    • false: 휘발성 Queue
      • Broker가 종료되면 휘발성 Queue들은 사라집니다.
      • 재시작 후 다시 사용하려면 새로 생성해야 합니다.
    • durable 속성은 메시지의 영속화와는 관련이 없는 Queue 자체의 속성입니다.
    • 메시지를 영속화 여부는 메시지의 Content Header에 delivery-mode를 기반으로 결정됩니다.
    • Queue가 Durable로 설정되어있더라도, 메시지가 Transient 라면 Broker 재시작 시 Queue는 보존되지만 메시지는 유실됩니다.
  • exclusive: 해당 Queue를 생성한 Connection만 접근할 수 있도록 하는 설정입니다.
    • true인 경우, 해당 Queue를 생성한 Connection이 닫히면 Queue도 자동으로 삭제됩니다.
  • auto-delete: Queue를 사용하던 모든 Consumer가 연결을 끊으면 Queue가 자동으로 삭제됩니다.

동작

  1. Exchange는 Binding을 사용해 메시지를 Queue에 삽입합니다.
  2. 메시지가 도착하면, Queue는 연결된 Consumer에게 즉시 메시지를 전달합니다.
  3. 메시지가 Consumer로 전달된 후, 해당 메시지를 승인 대기 상태로 전환합니다
    • 이때, Consumer로부터 성공/실패 응답을 받기 전까지 해당 메시지에 배타적 락을 걸어 다른 Consumer로 이중 전송되는 것을 방지합니다.
  4. Consumer가 처리를 완료하고 승인(ACK) 신호를 보내면, Queue는 메시지를 완전히 제거합니다.
  5. 소비자가 승인 전 연결을 끊거나 부정 승인(Reject)을 보내면, Queue는 락을 해제하고 메시지를 다시 대기열에 넣거나 제거합니다.
    • 거절된 메시지는 Reject Method Frame의 requeue 속성에 따라 처리됩니다.
      • requeue = true
        • 해당 메시지를 Queue의 맨 앞에 넣습니다. 이후 다시 Consumer에게 전달됩니다.
      • requeue = false
        • Queue에서 메시지를 제거합니다.
    • RabbitMQ는 DLX라는 특수한 Exchange로 메시지를 전송하기도 합니다.
    • RabbitMQ는 메시지의 재시도 카운트 개념을 통해 일정 횟수만 재시도하도록 하기도 합니다.

6. Consumer

설명

Broker로부터 메시지를 전달받아 소비하는 주체입니다.
Push받을 수 있는 메시지의 최대 허용량을 설정할 수 있습니다.
이를 통해 자신의 처리 역량에 맞춰 메시지 Push 속도를 조절함으로써, 부하를 방지합니다.

구조

  • consumer tag: Broker가 발급해주는 식별자로, Consumer를 유일하기 식별하기 위한 이름표입니다.
    • Consumer가 Queue를 구독하면, Broker는 consumer tag를 발행합니다.(구독 시 원하는 consumer tag도 명시 가능)
    • Queue에 메시지가 들어오면, 해당 Queue를 구독하는 consumer tag를 찾아 해당 Channel로 메시지를 전달합니다.
    • Consumer 입장에서, Channel로부터 전달받은 메시지가 어떤 Queue로부터 온 것인지 구분하기 위해 Broker는 메시지 Frame에 consumer tag를 붙여서 보냅니다.
  • channel: Consumer가 메시지를 전달받기 위한 Channel입니다.
  • acknowledgement mode: 메시지 수신응답 방식입니다.
    • acknowledgement mode: automatic
      • 메시지를 수신받은 후, 즉시 ACK를 반환합니다.
    • acknowledgement mode: explicit
      • 메시지를 수신받은 후, 클라이언트 로직(비즈니스 로직)을 수행한 다음 ACK를 반환합니다.
  • prefetch-count: Consumer가 ACK를 보내기 전까지 Broker가 한 번에 보낼 수 있는 메시지의 최대 갯수입니다.
    • 메시지를 전달받은 Consumer가 메시지를 처리하는 동안, Broker는 ACK를 기다리지 않고, prefetch-count만큼 메시지를 계속해서 전달합니다.
    • Consumer의 메시지 처리 속도를 고려하기 위해 존재합니다.

동작

  1. Broker에게 특정 Queue에 대한 Consumer 생성 명령을 전송합니다.
    • Basic.Consume Method Frame을 통해 이루어집니다.
    • 이 때, Basic.Consume Method Frame을 보낸 Channel 위에서 구독이 발생합니다.
    • Broker는 consumer tag를 생성한 후, Channel과 Queue 그리고 consumer tag를 연결하는 레코드를 생성합니다.
      • 구독 시 원하는 consumer tag를 명시할 수도 있습니다.
  2. Broker가 메시지를 발송합니다.
    • Broker는 Queue에 메시지 인입 시, 해당 Queue와 연결된 consumer tag를 찾고, 연결된 Channel로 메시지를 발송합니다.
  3. 메시지를 전달받은 Consumer는 acknowledgement mode에 따라 ACK를 응답합니다.

7. 마치며

여러분들은 그동안 Spring AMQP와 같은 라이브러리를 사용하며 메서드 하나로 메시지를 아주 편리하게 주고받았습니다.
잘 만들어진 도구들이 복잡한 내부 사정을 우아하게 감추어주었기 때문입니다.
이 방대한 명세서를 한 페이지씩 공부하지 않아도 비즈니스 로직을 구현하고 서비스를 배포하는 데에는 별다른 문제가 없습니다.

사실, 저는 RabbitMQ를 사용/운영해 본 경험이 없습니다.
이 사실에 실망하셨나요? 혹은 "써보지도 않았으면서 원리를 논하나?"라는 의구심이 드시나요?

‘사용’이란 무엇일까요?

사용하다: (사람이 사물을) 어떤 목적이나 기능에 맞게 필요로 하거나 소용이 되는 곳에 쓰다.
출처: 네이버 백과사전

현대 개발 시대에서, 많은 개발자들은 자신이 작성한 메서드 아래에 숨어 있는 블랙박스에는 관심을 가지지 않고, ‘동작’하는 것에 관심을 가집니다.
이것이 나쁘다는 이야기는 아닙니다. 내부의 복잡한 구조를 모르더라도, 문제를 해결하기 위한 다양한 라이브러리 활용법을 아는 것도 훌륭한 능력입니다.

그러나, 저는 코드 한 줄을 작성하는 것보다는 동작 원리를 학습하는 것이 더 재미있어 보였습니다.
RabbitMQ를 사용해 본 경험이 없더라도, 저는 이제 메시지 브로커를 잘 활용할 자신이 있습니다.

긴 글 읽어주셔서 감사합니다.

참고 문서
https://www.amqp.org/specification/0-9-1/amqp-org-download
Advanced Message Queuing Protocol (AMQP) Protocol Specification, Version 0-9-1

https://queue.acm.org/detail.cfm?id=1255424
Toward a Commodity Enterprise Middleware - John O'Hara, JPMorgan

profile
동작보단 원리를 좋아하는 머랭의 블로그입니다.

0개의 댓글