RabbitMQ 클러스터 고가용성 달성 가이드
RabbitMQ는 확장 가능하고 분산된 애플리케이션 구축에 널리 사용되는 강력한 오픈 소스 메시지 브로커입니다. 메시지 중개자 역할을 하여 다양한 서비스 간의 안정적인 통신을 보장합니다. 그러나 이러한 중요한 구성 요소에서 단일 장애 지점은 애플리케이션 중단 및 데이터 손실로 이어질 수 있습니다. 여기서 고가용성(HA)이 중요한 역할을 합니다.
이 가이드에서는 고가용성 RabbitMQ 클러스터 설정을 위한 핵심 개념과 모범 사례를 안내합니다. 메시지 내구성과 브로커 복원력을 달성하기 위한 두 가지 주요 메커니즘인 클래식 큐 미러링과 최신 쿼럼 큐를 살펴볼 것입니다. 이러한 전략을 이해하면 노드 장애가 발생해도 애플리케이션이 강력하고 반응성을 유지하도록 가동 중지 시간을 최소화하고 중요한 메시지 데이터를 보호하는 RabbitMQ 배포를 설계하고 구현할 준비가 될 것입니다.
RabbitMQ의 고가용성 이해
RabbitMQ의 고가용성이란 클러스터 내 하나 이상의 노드에 장애가 발생하더라도 메시징 시스템이 심각한 중단 없이 계속 작동할 수 있는 능력을 의미합니다. 이는 메시지 데이터와 구성을 여러 노드에 복제하여 달성되며, 한 노드를 사용할 수 없게 되면 다른 노드가 해당 책임을 원활하게 인수할 수 있도록 보장합니다.
HA RabbitMQ 설정의 주요 목표는 다음과 같습니다.
- 장애 허용: 시스템은 전체 서비스 중단 없이 개별 노드 장애를 견딜 수 있습니다.
- 데이터 내구성: 노드가 충돌하더라도 메시지가 손실되지 않습니다.
- 서비스 가동 시간: 지속적인 메시지 처리 기능을 유지합니다.
RabbitMQ HA를 위한 핵심 개념
특정 HA 메커니즘을 자세히 살펴보기 전에 몇 가지 기본적인 RabbitMQ 개념을 이해하는 것이 중요합니다.
클러스터링
RabbitMQ 클러스터는 네트워크를 통해 연결된 여러 RabbitMQ 노드로 구성됩니다. 이러한 노드는 공통 상태, 리소스(사용자, 가상 호스트, 교환, 큐 등)를 공유하고 워크로드를 분산할 수 있습니다. 클라이언트는 클러스터의 어떤 노드에든 연결할 수 있으며 메시지는 다른 노드에 있는 큐로 라우팅될 수 있습니다.
메시지 내구성
메시지 내구성은 데이터 손실을 방지하는 데 중요합니다. RabbitMQ에서는 두 가지 주요 설정을 통해 이를 달성합니다.
- 내구성 있는 큐: 큐를 선언할 때
durable인수를true로 설정하면 브로커가 다시 시작되어도 큐 정의 자체가 유지됩니다. 브로커가 다운되었다가 다시 시작되면 내구성 있는 큐는 계속 존재합니다. - 영구 메시지: 메시지를 게시할 때
delivery_mode를2(영구)로 설정하면 RabbitMQ는 게시자에게 확인하기 전에 메시지를 디스크에 씁니다. 따라서 브로커가 메시지를 소비자에게 전달하기 전에 충돌하면 브로커가 다시 시작될 때 메시지를 복구할 수 있습니다.
경고: 진정한 내구성을 위해서는 큐가 내구성 있어야 하고 메시지도 영구적이어야 합니다. 큐가 내구성 있지만 메시지가 영구적이지 않으면 브로커가 다시 시작될 때 메시지가 손실됩니다. 메시지가 영구적이지만 큐가 내구성 있지 않으면 큐 정의가 손실되어 메시지에 액세스할 수 없게 됩니다.
클래식 큐를 사용한 고가용성 달성: 큐 미러링
기존 또는 "클래식" 큐의 경우 고가용성은 주로 큐 미러링을 통해 달성됩니다. 이 메커니즘을 사용하면 클러스터의 여러 노드에 걸쳐 큐의 내용(메시지 포함)을 복제할 수 있습니다.
큐 미러링 작동 방식
큐가 미러링되면 한 노드를 마스터로 지정하고 다른 노드를 미러(또는 복제본)로 지정합니다. 큐에 대한 모든 작업(게시, 소비, 추가/제거)은 마스터 노드를 통해 수행됩니다. 그런 다음 마스터는 이러한 작업을 모든 미러 노드에 복제합니다. 마스터 노드에 장애가 발생하면 미러 중 하나가 새 마스터로 승격됩니다.
클래식 큐 미러링 구성
큐 미러링은 정책을 사용하여 구성됩니다. 정책은 이름으로 큐를 일치시키고 일련의 인수를 적용하는 규칙입니다.
rabbitmqctl 명령 또는 RabbitMQ 관리 UI를 사용하여 정책을 정의하는 방법의 예는 다음과 같습니다.
rabbitmqctl set_policy ha-all
"^my-ha-queue-" '{"ha-mode":"all"}' --apply-to queues
주요 매개변수를 분석해 보겠습니다.
ha-all: 정책 이름입니다."^my-ha-queue-":my-ha-queue-로 시작하는 큐 이름을 일치시키는 정규식입니다. 이 패턴과 일치하는 큐에만 정책이 적용됩니다."ha-mode":"all": 이 중요한 인수는 미러링 동작을 지정합니다.all: 클러스터의 모든 노드에 큐를 미러링합니다.exactly: 지정된 수의 노드에 큐를 미러링합니다 (ha-params에서 개수를 정의합니다).nodes: 특정 노드 목록에 큐를 미러링합니다 (ha-params에서 노드 이름을 정의합니다).
--apply-to queues: 이 정책이 큐에 적용됨을 지정합니다.
동기화 모드 (ha-sync-mode)
미러링된 큐는 다른 방식으로 동기화될 수 있습니다.
manual(기본값): 새로 추가된 미러 노드는 마스터와 자동으로 동기화되지 않습니다. 관리자는 수동으로 동기화를 트리거해야 합니다. 이는 자동 동기화가 노드 재시작 시 성능 문제를 일으킬 수 있는 대규모 큐에 유용합니다.automatic: 새 미러 노드는 클러스터에 참여하는 즉시 자동으로 마스터와 동기화됩니다. 일반적으로 관리가 더 간단하지만 일시적으로 성능에 영향을 줄 수 있습니다.
rabbitmqctl set_policy ha-auto-sync
"^important-queue-" '{"ha-mode":"exactly","ha-params":2,"ha-sync-mode":"automatic"}' --apply-to queues
이 정책은 ^important-queue-와 일치하는 큐를 정확히 2개의 노드에 미러링하며, 새 미러는 자동으로 동기화됩니다.
클래식 큐 미러링의 장단점
장점:
* 잘 구축되고 널리 이해됩니다.
* 노드 장애에 대해 우수한 복원력을 제공할 수 있습니다.
단점:
* 성능 오버헤드: 모든 작업이 마스터를 통과하므로 병목 현상이 발생할 수 있습니다. 미러로의 복제는 지연 시간을 추가합니다.
* 분할 두뇌 시나리오: 복잡한 네트워크 분할 상황에서는 여러 마스터가 선출되어 불일치가 발생할 수 있지만 RabbitMQ에는 이를 완화하는 메커니즘이 있습니다.
* 데이터 안전성: 미러링 중에는 마스터 장애 및 장애 조치 중에 마스터가 프로듀서에게 승인된 메시지를 완전히 복제하기 전에 실패하면 데이터가 손실될 수 있는 창이 있습니다.
* 새 노드에 대한 수동 동기화: ha-sync-mode: manual은 메시지 손실을 방지하기 위해 새 노드를 동기화하려면 수동 개입이 필요합니다.
최신 큐를 사용한 고가용성 달성: 쿼럼 큐
쿼럼 큐는 RabbitMQ 3.8에 도입된 최신 고가용성 큐 유형입니다. 이는 클래식 큐 미러링의 일부 제한 사항을 해결하도록 설계되었으며, 특히 엄격한 내구성이 필요한 사용 사례에 대해 더 강력한 데이터 안전 보장과 더 간단한 의미론을 제공합니다.
쿼럼 큐 작동 방식
쿼럼 큐는 Raft 합의 알고리즘을 기반으로 하며, 이는 여러 노드에 걸쳐 일관된 로그(큐 내용)를 유지하는 분산형 장애 허용 방식을 제공합니다. 단일 마스터 대신 쿼럼 큐는 리더와 여러 팔로워로 작동합니다. 쓰기 작업(메시지 게시)은 프로듀서에게 승인되기 전에 노드의 과반수(쿼럼)에 복제되어야 합니다. 이를 통해 리더에 장애가 발생해도 나머지 노드에서 일관된 상태를 복구할 수 있습니다.
클래식 큐 미러링에 대한 쿼럼 큐의 장점
- 더 강력한 내구성 보장: 메시지는 과반수 노드에 안전하게 복제된 후에만 승인되므로 리더 장애 시 데이터 손실 가능성이 크게 줄어듭니다.
- 자동 동기화: 모든 복제본은 항상 동기화됩니다. 새 노드가 참여하거나 오프라인 노드가 다시 온라인 상태가 되면 수동 개입 없이 자동으로 리더를 따라잡습니다.
- 간단한 구성: 복잡한
ha-mode또는ha-sync-mode매개변수가 없습니다. 복제 팩터만 정의하면 됩니다. - 일관된 동작: 네트워크 분할 시 예측 가능한 동작; 과반수만 진행할 수 있도록 하여 분할 두뇌 시나리오를 방지하도록 설계되었습니다.
쿼럼 큐 구성
쿼럼 큐를 만드는 것은 간단합니다. x-quorum-queue 인수로 선언합니다.
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
# 3개의 복제본으로 쿼럼 큐 선언
channel.queue_declare(
queue='my.quorum.queue',
durable=True, # 쿼럼 큐는 암시적으로 항상 내구성이 있지만 명시하는 것이 좋습니다.
arguments={'x-quorum-queue': 'true', 'x-max-replicas': 3}
)
print("쿼럼 큐 'my.quorum.queue'가 선언되었습니다.")
channel.close()
connection.close()
쿼럼 큐의 주요 인수:
x-quorum-queue: 'true': 큐를 쿼럼 큐로 지정합니다.x-max-replicas: 큐의 최대 복제본 수를 지정합니다. 기본값은 일반적으로 3입니다. 복제본 수가 홀수(3, 5 등)이면 더 나은 복원력과 성능을 위해 권장됩니다. 이는 쿼럼 크기에 직접적인 영향을 미치기 때문입니다.
팁: x-max-replicas의 경우 일반적으로 홀수 개의 복제본(예: 3개 또는 5개)이 권장됩니다. 복제본이 3개이면 쿼럼은 2개의 노드(2/3)입니다. 복제본이 5개이면 쿼럼은 3개의 노드(3/5)입니다. 이렇게 하면 (N-1)/2개의 노드가 손실되어도 큐는 계속 작동할 수 있습니다.
쿼럼 큐 사용 시기
쿼럼 큐는 일반적으로 다음을 위해 권장됩니다.
- 미션 크리티컬 데이터: 메시지 손실이 절대 용납되지 않는 경우.
- 고처리량 시나리오: 더 효율적인 복제로 인해 과부하 시 미러링된 클래식 큐보다 더 나은 처리량과 낮은 지연 시간을 제공할 수 있습니다.
- 간단한 HA 관리: 자동 동기화와 더 강력한 보장은 운영 복잡성을 줄입니다.
클래식 큐 미러링은 다음과 같은 경우에 여전히 적합할 수 있습니다.
- 마이그레이션이 쉽지 않은 레거시 시스템.
- 절대적인 일관성과 내구성이 최우선 과제가 아니며, 더 간단한 마스터-복제본 모델로 충분한 사용 사례.
브로커 복원력 및 내구성을 위한 전략
큐별 HA 메커니즘 외에도 진정한 복원력 있는 RabbitMQ 배포를 위해서는 더 광범위한 전략이 필수적입니다.
1. 영구 메시지 및 내구성 있는 큐
언급한 바와 같이, 모든 중요한 큐는 durable=True로 선언하고 브로커 재시작 후에도 유지되어야 하는 모든 메시지는 delivery_mode=2(영구)로 게시되도록 하십시오. 이것은 미러링 또는 쿼럼 큐와 관계없이 데이터 내구성에 대한 절대적인 기본 사항입니다.
2. 클라이언트 연결 처리 및 자동 복구
RabbitMQ 클라이언트 라이브러리(Python의 pika, Java의 amqp-client 등)는 자동 연결 및 채널 복구 기능을 제공합니다. 이러한 기능을 사용하도록 클라이언트를 구성하십시오. 노드 장애 또는 네트워크 문제가 발생하면 클라이언트는 자동으로 다시 연결하고, 채널을 재설정하고, 큐, 교환 및 바인딩을 다시 선언하려고 시도합니다.
예(pika, 간소화):
import pika
params = pika.ConnectionParameters(
host='localhost',
port=5672,
credentials=pika.PlainCredentials('guest', 'guest'),
heartbeat=60, # 하트비트 활성화
blocked_connection_timeout=300 # 차단된 연결 감지
)
# 자동 복구 활성화
connection = pika.BlockingConnection(params)
connection.add_callback_threadsafe(lambda: print("연결이 성공적으로 복구되었습니다!"))
3. 클라이언트 연결 부하 분산
최적의 성능과 복원력을 위해 RabbitMQ 클러스터의 모든 활성 노드에 클라이언트 연결을 분산하십시오. 이는 다음을 통해 달성할 수 있습니다.
- DNS 라운드 로빈: RabbitMQ 호스트 이름에 대한 여러 IP 주소를 반환하도록 DNS를 구성합니다.
- 전용 부하 분산기: 하드웨어 또는 소프트웨어 부하 분산기(예: HAProxy, Nginx)를 사용하여 클라이언트 연결을 분산합니다. 이를 통해 상태 확인을 통해 비정상적인 노드를 회전에서 제거할 수도 있습니다.
- 클라이언트 측 연결 문자열: 일부 클라이언트 라이브러리는 호스트 이름 목록을 지정할 수 있으며, 클라이언트는 순차적으로 또는 무작위로 시도합니다.
4. 모니터링 및 경고
고가용성을 유지하려면 사전 예방적 모니터링이 중요합니다. 다음을 위해 강력한 모니터링을 구현하십시오.
- 노드 상태: 각 RabbitMQ 노드의 CPU, 메모리, 디스크 I/O 사용량.
- RabbitMQ 지표: 큐 길이, 메시지 속도(게시, 소비, 미승인), 연결 수, 채널, 소비자 수.
- 클러스터 상태: 노드 연결, 정책 적용, 큐 동기화 상태.
중요 임계값(예: 큐 길이가 제한을 초과, 노드 오프라인, 높은 CPU 사용량)에 대한 경고를 설정하여 잠재적인 문제를 신속하게 대응할 수 있도록 합니다.
5. 백업 및 복원 전략
직접적인 HA 메커니즘은 아니지만, 강력한 백업 및 복원 전략은 재해 복구(DR)에 중요합니다. RabbitMQ 정의(교환, 큐, 사용자, 정책)를 정기적으로 백업하고, 필요한 경우 메시지 저장소(미러링/쿼럼 큐가 아닌 큐 또는 심각한 DR 시나리오의 경우)를 백업하십시오. 이를 통해 치명적인 데이터 손실 또는 클러스터 손상을 복구할 수 있습니다.
클래식 큐 미러링과 쿼럼 큐 중 선택
선택을 돕기 위한 빠른 가이드입니다.
| 특징 | 클래식 큐 미러링 (클래식 큐용) | 쿼럼 큐 |
|---|---|---|
| 데이터 안전성 | 약함; 마스터 장애 시 메시지 손실 가능성 | 더 강함; 쿼럼 쓰기 후 메시지 승인 |
| 일관성 | 분할 시 분할 두뇌 발생 가능성 있음 | 강력함 (Raft); 분할 두뇌 방지 |
| 복제 | 마스터/슬레이브 모델; ha-sync-mode 필요 |
리더/팔로워 (Raft); 자동 동기화 |
| 구성 | ha-mode, ha-params, ha-sync-mode를 포함한 정책 |
x-quorum-queue, x-max-replicas를 사용한 큐 선언 |
| 성능 | 마스터가 병목 현상일 수 있음 | 분산 쓰기로 인해 과부하 시 일반적으로 더 나은 성능 |
| 복잡성 | 동기화 및 복구를 위한 운영 복잡성 높음 | 더 간단함; 장애 조치 및 동기화 자동 처리 |
| 사용 사례 | 레거시 시스템, 덜 중요한 데이터 | 미션 크리티컬 데이터, 높은 내구성 요구 사항 |
새로운 배포, 특히 데이터 무결성이 가장 중요한 배포의 경우, 쿼럼 큐는 더 강력한 보장과 더 간단한 운영 모델 때문에 일반적으로 권장되는 선택입니다.
결론
RabbitMQ에서 고가용성을 달성하는 것은 복원력 있고 장애 허용 가능한 메시징 시스템을 구축하는 데 중요합니다. 클래식 큐 미러링 및 특히 최신 쿼럼 큐와 같은 전략을 이해하고 구현함으로써 메시지 내구성과 브로커 가동 시간을 크게 향상시킬 수 있습니다.
이러한 큐 수준 HA 메커니즘을 더 광범위한 아키텍처 고려 사항으로 보완하는 것을 잊지 마십시오. 내구성 있는 큐 및 영구 메시지 활용, 클라이언트 측 자동 복구 구성, 부하 분산기를 통한 클라이언트 연결 분산, 강력한 모니터링 및 재해 복구 계획 구현. 이러한 접근 방식을 결합하여 내결함성을 갖춘 RabbitMQ 인프라를 구축하여 애플리케이션에 대한 지속적이고 안정적인 메시지 전달을 보장할 수 있습니다.