[AMQP] - RabbitMQ ACK, Exchange, Route

KimJiHong·2023년 12월 23일
1

Django and API

목록 보기
9/9

해당 게시글에서 RabbitMQ에 대해 추가 설명하는 부분입니다.
따라서, Queue구조 나 Producer, Broker, Worker에 대한 설명은 생략 하겠습니다.

RabbitMQ

RabbitMQAMQP를 구현한 Message broker 시스템으로
Producer에서 consumer로 메시지를 전달할 때 중간에서 징검다리 역할을 한다.

AMQP?

AMQP(Advanced Message Queuing Protocol)은 분산 시스템에서 Message 큐 시스템 간에 사용되는 표준화된 프로토콜을 의미한다. 즉, ExchangeRouting을 통해 Producer와 Consumer 사이에서 Message를 안전하게 교환, Queue와 Message Broker간의 효과적인 상호 작용을 관리한다.

Celery를 사용할 때, Broker 역할은 Redis와 RabbitMQ가 많이 사용되는데 RabbitMQ를 Broker로 사용하면 Producer와 Consumer간의 Message 교환을 안전하게 보장해준다.

어떻게 안정성을 보장한다는 것일까?

Acknowledge

RabbitMQ는 Producer와 Consumer 사이에 성공적인 Message 전달을 보장하기 위해서 ACK(Acknowledge) 기법을 사용한다.

ACK 기법은 ConsumerRabbitMQ로 부터 메시지를 받으면 AcknowledgeBroker(RabbitMQ)로 전송하는 Consumer Acknowledgement 과정과 RabbitMQ가 Producer로 부터 메시지를 받으면 AcknowledgeProducer로 보내는 과정인 Producer Confirm이 있다.

  • Producer Confirm 과정
    1. Producer가 RabbitMQ(broker)로 메시지를 보냄.
    2. RabbitMQ는 정상적으로 메시지를 받으면 ACK를 Producer로 보냄.
  • Consumer Acknowledgement 과정
    1. RabbitMQ(broker)가 Consumer로 메시지를 보냄.
    2. Consumer는 정상적으로 메시지를 받으면 ACK를 RabbitMQ로 보냄.

즉, ACK 기법은 각 부분에서 Message를 보낸 뒤 ACK를 받으면 Message가 정상적으로 receive된 것이라고 판단하고, ACK를 받지 못하면 다시 Message를 전송함으로써 "At Least Once" 를 보장할 수 있다.

Reject vs NACK

RejectNACK는 둘다 ConsumerRabbitMQ로 부터 수신한 메시지를 처리하는 도중 어떤 문제가 발생했을 때 메시지를 다시 Queue로 되돌리는(선택) 매커니즘이다.

  • Reject
    • 수신한 특정 메시지를 거부하면서 다시 Queue로 되돌릴 지의 여부를 선택.
    • 하나의 메시지에 대한 처리만 가능.
    • 즉, 개별 메시지에 대한 처리 결과를 파악할 수 있음.
  • NACK (Negative Acknowledge)
    • 수신한 여러 메시지를 한번에 거부하면서 다시 Queue로 되돌릴 지의 여부를 선택.
    • 여러 메시지에 대한 처리를 한번에 가능.
    • 즉, 여러 메시지에 대한 처리로 대량의 메시지를 효율적으로 처리 가능.

Idempotent

ACK 기법를 사용함으로 써 "At Least Once" 적어도 한번은 메시지를 보장할 수 있다.

하지만, 각 부분의 수신자가 Network 이슈로 메시지를 정상적으로 받았음에도 ACK를 전송하지 못할 수 있다.

이 경우엔 ACK 기법에 의해 송신자 측에서는 수신자가 정상적으로 메시지를 받지 못했다고 생각해 메시지를 재전송하게 된다. (At Least Once 충실.)

이로 인해, 수신자 측에서는 같은 메시지(작업)를 2번 실행하거나 저장할 수도 있는 상황이 생길 수 있다.

따라서 우리는 멱등성(Idempotent) 즉, 동일한 Message를 여러번 수신하더라도 동작에 이상이 없도록 고려하여 구현해야 한다.

Idempotent에 대해 수학적으로 예를 들어 보자.

f(x) = f(f(x)) = f(f(f(x))) (단, f(x)는 실제 프로그래밍 Fuction)

이렇게 함수를 여러번 실행하더라도 같은 하나의 결과를 가지게 구현하여
Network 이슈와 같이 ACK를 수신하지 못해 메시지(작업)를 재전송해도 하나의 통일된 결과를 가지게 된다.



Routing & Exchange

RoutingExchange는 Broker(RabbitMQ)에서 Producer로부터 받은 메시지를 효과적으로 분배하고 전달하기 위해 사용한다.

Routing

Binding

Binding은 Exchange와 Queue를 연결하는 것으로 어떤 Exchange가 어떤 Queue에게 메시지를 보내야 하는지를 정의하는 규칙이다.

아래에서 설명 하겠지만, Exchange는 메시지를 받아서 어떤 Queue로 보낼지 결정하는 역할을 하는데, Binding은 이 Exchange와 특정 Queue간의 연결을 설정한다. 이렇게 설정된 Binding은 특정 규칙을 기반으로 메시지가 Exchange에서 Queue전달되는 방식을 지정하는 것이다.

요약하면, BindingExchangeQueue간의 연결을 설정하여 어떤 조건에 따라 메시지가 전송되는지를 결정한다.

Routing KEY

Routing KEY는 메시지가 어떤 특정한 Queue로 라우팅되는데 사용되는 일종의 "식별자"이다.
Exchange에서는 Routing KEY는 통해 어떤 Queue로 메시지를 전달할지 목적지를 선택한다.

Exchange

ExchangeProducer로부터 받은 메시지를 적절한 Queue로 라우팅하는 중간 매개체의 역할을 한다.

즉, Producer가 Broker의 Exchange에게 메시지를 전송하면 특정한 Queue로 전달하거나 Fanout해서 여러 Queue로 전달한다.

RabbitMQ에는 아래의 4가지 Exchange 유형이 있다.

  • Direct Exchange (Default Exchange)
    • Routing Key와 일치하는 Queue로 직접 라우팅
  • Fanout Exchange
    • 연결된 모든 Queue에 메시지를 전달 (Broadcast)
  • Topic Exchange
    • 메시지의 Pattern을 통해 해당 패턴과 일치하는 Queue들로 라우팅
  • Headers Exchange
    • 메시지의 Header 속성과 일치하는 Queue로 라우팅

Direct Exchange

Direct ExchangeProducer가 Exchange로 메시지를 보낼 때, 특정 Routing Key를 포함해서 보내 Exchange에서 해당 Key와 일치하는 Queue로만 메시지를 전송한다.

예를 들어, 결제를 담당하는 'A'와 장바구니를 담당하는 'B'가 Exchange에 binding되어 있으면
Producer결제 담당 Queue에 메시지를 전달하고 싶을 땐 Routing KEY를 "A"
장바구니를 담당하는 Queue에 메시지를 전달하고 싶을 땐 Routing KEY를 "B"로 설정하여 보내면 된다.

# Example.1 Direct Exchange:

Routing KEY = AAAA.bbbb

# Queue name (result)
AAAA.bbbb (메시지 전달 O)
AAAA.BBBB (메시지 전달 X)
AAAA.bbbb.CCCC (메시지 전달 X)

Producer가 Exchange를 명시하지 않고 메시지를 전송하면 Direct Exchange 방식으로 전송한다.
(Default Exchange)

Fanout Exchange

Fanout Exchange는 Producer에게 메시지를 받으면 바인딩된 모든 Queue 즉, 연결된 모든 큐로 메시지를 전달한다.

예를 들어, Producer가 Sport_news라는 Exchange로 메시지를 전송하면
Routing Key의 유무에 상관없이 Sport_news에 바인딩 된 모든 큐 Queue A, Queue B, Queue C로 메시지를 전달한다.
따라서, 메시지를 전달 받은 각 Queue들은 독립적으로 메시지를 처리한다.

# Example.1 Fanout Exchange:

Routing KEY = AAAA.bbbb

# Queue name (result)
AAAA.bbbb (메시지 전달 O)
MMMM.bbbb (메시지 전달 O)
AAAA.bbbb.CCCC (메시지 전달 O)

Topic Exchange

Topic Exchange는 Producer가 보낸 메시지의 Routing KEY와 동일한 패턴을 가지는 Queue로 라우팅한다.

Routing KEY에 정확하게 일치하는 패턴(*)과 매칭할 것인지, 여러 패턴(#)과 매치할 것인지 패턴을 정하는 "와일드 카드"를 사용한다.

# Example.1 Topic Exchange: wildcard '*'

Routing KEY = AAAA.*

# Queue name (result)
AAAA.bbbb (메시지 전달 O)
MMMM.bbbb (메시지 전달 X)
AAAA.bbbb.CCCC (메시지 전달 X)
# Example.2 Topic Exchange: wildcard '#'

Routing KEY = AAAA.#

# Queue name (result)
AAAA.bbbb.CCCC (메시지 전달 O)
AAAA.kkkk.MMMM.llll (메시지 전달 O)
MMMM.bbbb (메시지 전달 X)

Headers Exchange

Headers ExchangeProducer가 Exchange로 메시지를 보낼 때, 메시지의 헤더 정보를 기반으로 메시지를 특정 Queue로만 라우팅한다.
각 Queue들은 Exchange에 바인딩될 때 지정한 헤더 Key-Value 조합에 따라 메시지를 수신한다.

# Example. Headers Exchange:
Routing KEY : AAAA.bbbb / Header { "KEY": "Value-1" }

# Queue name (result)
AAAA.bbbb / Header { "KEY": "Value-1" } (메시지 전달 O)
MMMM.bbbb / Header { "KEY": "Value-1" } (메시지 전달 X)
AAAA.bbbb / Header { "KEY": "Value-2" } (메시지 전달 X)

Ref.

https://www.rabbitmq.com/
https://github.com/LeanKit-Labs/wascally/issues/84
https://medium.com/@vinciabhinav7/rabbitmq-overview-of-a-message-broker
https://www.cloudamqp.com/blog/part4-rabbitmq-exchange-routing
https://ssup2.github.io/theory_analysis/RabbitMQ_Ack/
https://phsun102.tistory.com/145

profile
대충 할거면 시작도 하지 말자.

0개의 댓글