RabbitMQ 클러스터로 고가용성(HA)을 달성하기 위한 가이드
클러스터링, 쿼럼 큐, 지속적 메시지, 클라이언트 복구, 로드 밸런싱 및 실용적인 모니터링을 통해 RabbitMQ HA를 구축합니다.
RabbitMQ 클러스터로 고가용성 달성 가이드
RabbitMQ 고가용성은 명확한 장애 질문에서 시작됩니다. 하나의 브로커 노드가 사라지면 퍼블리셔, 컨슈머 및 대기 중인 메시지는 어떻게 될까요? 단일 RabbitMQ 노드는 단일 장애 지점이 될 수 있으므로, 프로덕션 시스템은 일반적으로 클러스터링, 복제된 큐, 지속적 메시지 및 클라이언트 재연결 로직을 결합합니다.
새로운 RabbitMQ 배포의 경우 쿼럼 큐가 일반적인 HA 선택입니다. 클래식 미러링된 큐는 수년간 사용되지 않다가 RabbitMQ 4.0에서 제거되었으므로, 이전 클러스터에 대한 레거시 전용 지침으로 취급하십시오.
RabbitMQ의 고가용성 이해
RabbitMQ의 고가용성은 클러스터 내 하나 이상의 노드가 실패하더라도 메시징 시스템이 심각한 중단 없이 계속 작동할 수 있는 능력을 말합니다. 이는 여러 노드에 메시지 데이터와 구성을 복제하여 장애 조치 후 다른 노드가 큐를 계속 제공할 수 있도록 함으로써 달성됩니다.
HA RabbitMQ 설정의 주요 목표는 다음과 같습니다:
- 내결함성: 개별 노드 장애에도 전체 서비스 중단 없이 시스템을 견딜 수 있습니다.
- 데이터 지속성: 노드가 충돌하더라도 메시지가 손실되지 않습니다.
- 서비스 가동 시간: 지속적인 메시지 처리 기능을 유지합니다.
RabbitMQ HA의 핵심 개념
특정 HA 메커니즘을 살펴보기 전에 몇 가지 기본 RabbitMQ 개념을 이해하는 것이 중요합니다.
클러스터링
RabbitMQ 클러스터는 네트워크를 통해 연결된 여러 RabbitMQ 노드로 구성됩니다. 이러한 노드는 공통 상태, 리소스(사용자, 가상 호스트, 익스체인지 및 큐 등)를 공유하고 워크로드를 분산할 수 있습니다. 클라이언트는 클러스터의 모든 노드에 연결할 수 있으며, 메시지는 다른 노드에 있는 큐로 라우팅될 수 있습니다.
메시지 지속성
메시지 지속성은 데이터 손실을 방지하는 데 중요합니다. RabbitMQ에서는 두 가지 주요 설정을 통해 이를 달성합니다.
- 지속적 큐: 큐를 선언할 때
durable인수를true로 설정하면 큐 정의 자체가 브로커 재시작 후에도 유지됩니다. 브로커가 다운되었다가 다시 시작되면 지속적 큐는 계속 존재합니다. - 지속적 메시지: 메시지를 게시할 때
delivery_mode를2로 설정하면 메시지가 지속적으로 표시됩니다. 퍼블리셔 확인과 함께 사용하면 퍼블리셔는 RabbitMQ가 메시지에 대한 책임을 수락했음을 알 수 있습니다.
경고: 진정한 지속성을 위해서는 큐가 지속적이어야 하고 메시지도 지속적이어야 합니다. 큐가 지속적이지만 메시지가 지속적이지 않으면 브로커 재시작 시 메시지가 손실됩니다. 메시지가 지속적이지만 큐가 지속적이지 않으면 큐 정의가 손실되어 메시지에 접근할 수 없게 됩니다.
클래식 미러링된 큐를 사용한 레거시 HA
클래식 큐 미러링은 RabbitMQ 3.x에서 클러스터 노드 간에 클래식 큐를 복제했습니다. RabbitMQ 4.x에서는 사용할 수 없습니다. 이전 클러스터를 실행하는 경우 ha-mode를 사용하는 정책이 여전히 표시될 수 있지만, 새로운 설계는 대신 쿼럼 큐를 사용해야 합니다.
큐 미러링 작동 방식
큐가 미러링되면 하나의 노드를 마스터로 지정하고 다른 노드를 미러(또는 복제본)로 지정합니다. 큐에 대한 모든 작업(게시, 소비, 메시지 추가/제거)은 마스터 노드를 통해 진행됩니다. 그런 다음 마스터는 이러한 작업을 모든 미러 노드에 복제합니다. 마스터 노드가 실패하면 미러 중 하나가 새 마스터로 승격됩니다.
레거시 구성 예시
이전 RabbitMQ 3.x 클러스터는 정책을 사용하여 미러링을 구성했습니다.
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개의 노드에 미러링하고 새 미러는 자동으로 동기화됩니다.
클래식 큐 미러링의 장단점
장점:
- 잘 정립되어 있고 널리 이해됩니다.
- 노드 장애에 대한 우수한 복원력을 제공할 수 있습니다.
단점:
- 성능 오버헤드: 모든 작업이 마스터를 통해 이루어지므로 병목 현상이 발생할 수 있습니다. 미러에 대한 복제는 지연 시간을 추가합니다.
- 네트워크 파티션 복잡성: 파티션 처리 및 장애 조치 동작이 쿼럼 큐보다 추론하기 어려웠습니다.
- 데이터 안전성: 미러링되지만 마스터 장애 및 장애 조치 중에 생산자에게 확인된 메시지를 마스터가 완전히 복제하기 전에 실패하면 데이터가 손실될 수 있는 기간이 있습니다.
- 새 노드에 대한 수동 동기화:
ha-sync-mode: manual은 메시지 손실을 방지하기 위해 새 노드를 동기화하려면 수동 개입이 필요합니다.
최신 큐로 고가용성 달성: 쿼럼 큐
쿼럼 큐는 데이터 안전성과 예측 가능한 장애 조치를 위해 설계된 복제된 지속적 큐입니다. Raft를 사용하며 클래식 미러링된 큐의 권장 대체품입니다.
쿼럼 큐 작동 방식
쿼럼 큐는 Raft 합의 알고리즘을 기반으로 하며, 여러 노드에 걸쳐 일관된 로그(큐 콘텐츠)를 유지하는 분산된 내결함성 방법을 제공합니다. 단일 마스터 대신 쿼럼 큐는 리더와 여러 팔로워로 작동합니다. 쓰기 작업(메시지 게시)은 생산자에게 확인되기 전에 노드의 **과반수(쿼럼)**에 복제되어야 합니다. 이는 리더가 실패하더라도 나머지 노드에서 일관된 상태를 복구할 수 있도록 보장합니다.
클래식 큐 미러링 대비 쿼럼 큐의 장점
- 더 강력한 지속성 보장: 메시지는 노드 과반수에 안전하게 복제된 후에만 확인되므로 리더 장애 시 데이터 손실 가능성이 크게 줄어듭니다.
- 자동 동기화: 모든 복제본은 항상 동기화됩니다. 새 노드가 조인하거나 오프라인 노드가 다시 온라인 상태가 되면 수동 개입 없이 자동으로 리더를 따라잡습니다.
- 더 간단한 구성: 복잡한
ha-mode또는ha-sync-mode매개변수가 없습니다. 복제 요소를 정의하기만 하면 됩니다. - 일관된 동작: 네트워크 파티션에서 예측 가능한 동작; 과반수만 진행할 수 있도록 하여 스플릿 브레인 시나리오를 방지하도록 설계되었습니다.
쿼럼 큐 구성
쿼럼 큐를 만드는 것은 간단합니다. x-queue-type을 quorum으로 설정하여 큐를 선언합니다.
import pika
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
# 3개의 복제본이 있는 쿼럼 큐 선언
channel.queue_declare(
queue='my.quorum.queue',
durable=True,
arguments={
'x-queue-type': 'quorum',
'x-quorum-initial-group-size': 3
}
)
print("쿼럼 큐 'my.quorum.queue'가 선언되었습니다.")
channel.close()
connection.close()
쿼럼 큐의 주요 인수:
x-queue-type: 'quorum': 큐를 쿼럼 큐로 지정합니다.x-quorum-initial-group-size: 초기 큐 멤버 수를 설정합니다. 많은 배포에서 클러스터 크기와 장애 허용 범위에 따라 3개 또는 5개의 멤버를 사용합니다.
팁: 쿼럼 큐의 경우 일반적으로 홀수 개의 멤버(예: 3 또는 5)를 권장합니다. 3개의 멤버가 있는 경우 쿼럼은 2개의 노드입니다. 5개의 멤버가 있는 경우 쿼럼은 3개의 노드입니다. 이를 통해 소수의 멤버가 손실된 후에도 큐가 계속 작동할 수 있습니다.
쿼럼 큐를 사용해야 하는 경우
쿼럼 큐는 일반적으로 다음에 권장됩니다.
- 미션 크리티컬 데이터: 메시지 손실이 절대 허용되지 않는 경우.
- 예측 가능한 복제 큐: 아키텍처가 미러링된 클래식 큐보다 더 안전한 장애 조치와 명확한 일관성 동작을 위해 설계되었습니다.
- 더 간단한 HA 관리: 자동 동기화와 더 강력한 보장으로 운영 복잡성이 줄어듭니다.
클래식 큐 미러링은 다음 경우에 여전히 적합할 수 있습니다.
- 아직 마이그레이션할 수 없는 레거시 RabbitMQ 3.x 시스템.
- 쿼럼 큐로의 계획된 이동 중 임시 호환성.
브로커 복원력 및 지속성을 위한 전략
큐별 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)
Pika의 BlockingConnection은 다른 일부 클라이언트와 동일한 투명한 토폴로지 복구 모델을 제공하지 않습니다. Python에서는 연결 생성, 채널 설정, 선언, 컨슈머 및 퍼블리셔 확인을 재시도 로직으로 래핑하여 앱이 재연결 후 상태를 재구축할 수 있도록 합니다.
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-queue-type=quorum 및 선택적 x-quorum-initial-group-size가 있는 큐 선언 |
| 성능 | 마스터가 병목 현상이 될 수 있음 | 더 안전한 복제; 워크로드 벤치마킹 |
| 복잡성 | 동기화 및 복구를 위한 더 높은 운영 복잡성 | 더 간단함; 장애 조치 및 동기화 자동 처리 |
| 사용 사례 | 레거시 시스템, 덜 중요한 데이터 | 미션 크리티컬 데이터, 높은 지속성 요구 사항 |
특히 데이터 무결성이 가장 중요한 새로운 배포의 경우, 쿼럼 큐는 일반적으로 더 강력한 보장과 더 간단한 운영 모델로 인해 권장되는 선택입니다.
핵심 내용
새로운 RabbitMQ HA 작업의 경우 쿼럼 큐, 지속적 선언, 지속적 메시지, 퍼블리셔 확인 및 클라이언트 재연결 로직을 사용하십시오. 클러스터 앞에 로드 밸런서 또는 다중 호스트 클라이언트 구성을 배치한 다음 노드 상태, 큐 깊이, 확인되지 않은 메시지, 디스크 알람, 메모리 알람 및 컨슈머 수에 대해 알림을 설정하십시오.
여전히 클래식 미러링된 큐를 실행 중이라면 마이그레이션을 계획하십시오. 이는 레거시 동작이며 RabbitMQ 4.x는 클래식 큐 미러링을 제거했습니다.