신뢰할 수 있는 메시징을 위한 지속성 큐와 익스체인지 구성
RabbitMQ 큐, 익스체인지, 바인딩 및 지속성 메시지를 구성하여 브로커 재시작 시 중요한 작업이 손실되지 않도록 합니다.
신뢰할 수 있는 메시징을 위한 지속성 큐와 익스체인지 구성
애플리케이션이 작업, 주문 또는 알림에 RabbitMQ를 사용할 때, 브로커 재시작으로 인해 큐에서 대기 중인 작업이 사라져서는 안 됩니다. 지속성 큐, 지속성 익스체인지, 지속성 바인딩 및 지속성 메시지는 RabbitMQ가 재시작에도 안정적으로 동작하도록 하는 요소입니다.
이 가이드는 필요한 설정, 일반적으로 실수하기 쉬운 부분, 그리고 프로덕션 환경에서 신뢰하기 전에 동작을 확인하는 방법을 설명합니다.
지속성(Durability)과 영속성(Persistence) 이해하기
설정에 앞서, 메시지 생존과 관련된 두 가지 주요 개념을 구분하는 것이 중요합니다.
- 큐 지속성: 큐 정의 자체를 의미합니다. 지속성 큐 정의는 브로커 재시작 후에도 유지됩니다. 큐가 비지속성으로 선언되면 브로커가 중지될 때 삭제됩니다.
- 익스체인지 지속성: 익스체인지 정의를 의미합니다. 지속성 익스체인지는 재시작 후에도 유지되며, 비지속성 익스체인지는 브로커가 중지될 때 제거됩니다.
- 바인딩 지속성: 지속성 익스체인지와 지속성 큐 간의 바인딩은 지속성 토폴로지와 함께 복구됩니다. 임시 엔터티와 관련된 바인딩은 해당 엔터티와 함께 사라집니다.
- 메시지 영속성: 개별 메시지가 처리되는 방식을 의미합니다. 지속성 메시지는 브로커에 의해 디스크에 기록되어, 큐 자체가 지속성인 경우 브로커 재시작 후에도 유지됩니다. 임시(비지속성)로 표시된 메시지는 메모리에만 보관되며 재시작 중 손실될 수 있습니다.
메시지가 브로커 재시작 후에도 유지되려면 큐가 지속성이어야 하고 메시지가 지속성으로 발행되어야 합니다. 일반적인 라우팅 발행에서는 익스체인지와 바인딩도 복구되어 생산자와 소비자가 동일한 토폴로지를 계속 사용할 수 있어야 합니다.
1단계: 지속성 큐 선언
큐는 생성 시 명시적으로 지속성으로 선언되어야 합니다. 이는 RabbitMQ가 큐 메타데이터를 디스크에 저장하여 브로커가 다시 온라인 상태가 될 때 자동으로 다시 생성할 수 있도록 합니다.
이 구성은 일반적으로 브로커에 연결하는 클라이언트 라이브러리(AMQP 클라이언트)를 통해 수행됩니다. 아래는 일반적인 도구에서의 선언 예시입니다.
rabbitmqadmin CLI(또는 유사 도구) 사용 예시
명령줄 도구를 사용하여 큐를 선언할 때 durable 인수를 true로 지정합니다.
# 'high_priority_tasks'라는 큐를 지속성으로 선언하는 명령
rabbitmqadmin declare queue name=high_priority_tasks durable=true
Python(pika 라이브러리) 사용 예시
프로그래밍 방식에서는 channel.queue_declare() 메서드의 durable 매개변수를 True로 설정해야 합니다.
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
queue_name = 'order_processing_queue'
channel.queue_declare(
queue=queue_name,
durable=True # <-- 여기서 지속성 설정
)
print(f"Queue '{queue_name}' declared as durable.")
# connection.close() # (다른 작업 후 연결 종료)
큐 선언 주의사항: 이미 존재하는 큐를 다른 속성(예: 비지속성에서 지속성으로 변경)으로 다시 선언하려고 하면 RabbitMQ는 오류(
Precondition Failed등)를 발생시킵니다. 기존 큐의 지속성 상태는 변경할 수 없기 때문입니다.
2단계: 지속성 익스체인지 선언
메시지를 큐로 라우팅하는 익스체인지도 브로커 재시작 후에도 유지되어야 하는 경우 지속성으로 선언해야 합니다. 익스체인지가 비지속성인 경우 재시작 시 삭제되며, 관련된 모든 바인딩도 손실됩니다.
Python(pika 라이브러리)을 사용한 익스체인지 선언 예시
큐와 마찬가지로 익스체인지도 선언 시 durable 인수를 True로 설정해야 합니다.
import pika
# 연결과 채널이 이미 설정되었다고 가정
exchange_name = 'critical_events_exchange'
channel.exchange_declare(
exchange=exchange_name,
exchange_type='direct',
durable=True
)
print(f"Exchange '{exchange_name}' declared as durable.")
3단계: 지속성 메시지 발행
지속성 큐와 익스체인지를 선언하는 것은 토폴로지만 유지되도록 보장합니다. 메시지 자체가 유지되도록 하려면 발행자가 메시지 속성을 지속성으로 설정해야 합니다.
발행 시 delivery_mode 속성을 2(지속성을 의미)로 설정합니다.
예시: 지속성 메시지 발행(Pika)
channel.basic_publish 호출에서 properties 인수를 사용하여 메시지 지속성을 설정합니다.
import pika
from pika import BasicProperties
# ... 채널 설정 ...
message_body = "This order must not be lost!"
exchange = 'critical_events_exchange'
routing_key = 'urgent'
channel.basic_publish(
exchange=exchange,
routing_key=routing_key,
body=message_body,
properties=BasicProperties(
delivery_mode=2 # <-- 전송 모드 2 = 지속성
)
)
print("Message published persistently.")
모범 사례: 발행자 확인(Publisher Confirms): 지속성은 브로커 재시작 중 데이터를 저장하지만, 발행자 애플리케이션이 충돌하기 전에 브로커가 메시지를 수신했는지 보장하지는 않습니다. 최대 신뢰성을 위해 항상 지속성/영속성 구성을 발행자 확인과 함께 사용하여 브로커가 메시지를 안전하게 디스크에 기록했음을 확인하세요.
4단계: 지속성 구성 요소 바인딩
지속성 큐와 지속성 익스체인지가 생성되면 함께 바인딩해야 합니다. 바인딩은 라우팅 로직을 정의합니다. 익스체인지가 지속성인 경우 관련 바인딩도 일반적으로 지속성이어야 브로커 재시작 후 라우팅 구조가 즉시 작동합니다.
# ... 채널 설정 ...
exchange_name = 'critical_events_exchange'
queue_name = 'order_processing_queue'
routing_key = 'urgent'
channel.queue_bind(
exchange=exchange_name,
queue=queue_name,
routing_key=routing_key
)
print(f"Binding established between {exchange_name} and {queue_name}.")
RabbitMQ에서 지속성 큐와 지속성 익스체인지 간의 바인딩은 지속성입니다. 어느 한쪽이 임시인 경우 바인딩은 해당 엔터티보다 오래 지속될 수 없습니다.
신뢰성 체크리스트 요약
브로커 장애에 대비한 종단 간 메시지 신뢰성을 달성하려면 세 가지 구성 요소가 모두 올바르게 설정되었는지 확인하세요.
| 구성 요소 | 필요한 설정 | 목적 |
|---|---|---|
| 큐 | durable=True |
브로커 재시작 후 유지(메타데이터 저장). |
| 익스체인지 | durable=True |
브로커 재시작 후 유지(토폴로지 저장). |
| 바인딩 | 지속성 큐를 지속성 익스체인지에 바인딩 | 재시작 후 라우팅 관계 복구. |
| 메시지 | delivery_mode=2 (지속성) |
브로커 재시작 후 유지(데이터 디스크 기록). |
핵심 요약
RabbitMQ에서 지속성은 단일 스위치가 아닙니다. 지속성 큐와 익스체인지를 선언하고, 지속성 엔터티를 바인딩하며, delivery_mode=2로 메시지를 발행하고, 발행자 확인을 활성화하여 발행자가 RabbitMQ가 메시지를 수락했음을 알 수 있도록 하세요. 그런 다음 비프로덕션 브로커를 재시작하여 큐, 바인딩 및 소비되지 않은 지속성 메시지가 여전히 존재하는지 확인하세요.