신뢰할 수 있는 메시징을 위한 지속성 큐와 익스체인지 구성

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가 메시지를 수락했음을 알 수 있도록 하세요. 그런 다음 비프로덕션 브로커를 재시작하여 큐, 바인딩 및 소비되지 않은 지속성 메시지가 여전히 존재하는지 확인하세요.