Network of Brokers에서 'Bridge'가 메시지를 가져가는 기준은?
엔터프라이즈 환경에서 단일 메시지 브로커의 물리적 한계(CPU, 메모리, 커넥션 수)를 돌파하기 위해 도입하는 스케일 아웃(Scale-out) 아키텍처가 바로 'Network of Brokers (NoB)'입니다. 여러 대의 브로커를 하나로 묶어 거대한 클러스터처럼 동작하게 만드는 이 기술의 중심에는 브로커와 브로커 사이를 연결하는 '브릿지(Bridge)'라는 논리적 파이프라인이 존재합니다.
많은 인프라 엔지니어들이 이 브릿지를 단순히 "A 브로커에 들어온 모든 메시지를 B 브로커로 무조건 복사해 주는 멍청한 터널"이라고 오해하곤 합니다. 하지만 트래픽이 초당 수만 건에 달하는 환경에서 메시지를 무작정 복사한다면 네트워크 대역폭은 순식간에 고갈될 것입니다.
사실 브릿지는 매우 영악하고 지능적인 '내부 컨슈머(Internal Consumer)'입니다. 브릿지가 원격 브로커로 메시지를 넘길지 말지 결정하는 데에는 매우 엄격하고 정교한 아키텍처적 기준들이 작용합니다. 본 가이드에서는 브릿지가 메시지를 가져가는 핵심 원리와 이를 통제하는 필수 파라미터들을 상세히 해부합니다.

1. 절대 원칙: Demand-Forwarding (수요 기반 전달)
ActiveMQ Network of Brokers의 가장 근본적인 메시지 라우팅 원칙은 "수요(Demand)가 없는 곳으로는 메시지를 보내지 않는다"입니다.
브릿지가 연결되었다고 해서 A 브로커(Local)에 쌓인 메시지가 B 브로커(Remote)로 즉시 넘어가지 않습니다. 브릿지는 B 브로커 쪽에 해당 큐(Queue)나 토픽(Topic)을 구독하고 있는 '실제 살아있는 컨슈머 애플리케이션'이 존재하는지 끊임없이 감시합니다.
- 동작 방식: B 브로커에 특정 큐를 리스닝하는 컨슈머가 접속하면, B 브로커는 이 '구독 정보(Advisory Message)'를 브릿지를 통해 A 브로커에게 알립니다. 그제야 A 브로커의 브릿지가 열리며 메시지를 B 브로커 쪽으로 끌어가기(Pull) 시작합니다.
- 아키텍처적 이점: 컨슈머가 없는 브로커로 무의미한 메시지가 넘어가 디스크와 네트워크 자원을 낭비하는 현상을 완벽하게 차단합니다.
2. 로컬 우선주의: decreaseNetworkConsumerPriority
수요 기반 전달 원칙에 따라, 만약 A 브로커에도 컨슈머가 있고 B 브로커에도 컨슈머가 있다면 브릿지는 어떻게 동작할까요?
아무런 설정을 하지 않으면, A 브로커에 들어온 메시지는 라운드 로빈(Round-Robin) 방식으로 한 번은 로컬 컨슈머에게, 한 번은 브릿지를 타고 B 브로커의 컨슈머에게 전달됩니다. 하지만 굳이 바로 옆에 처리할 수 있는 로컬 컨슈머를 두고, 무거운 네트워크 홉(Hop)을 건너 B 브로커로 메시지를 보내는 것은 심각한 인프라 낭비입니다.
이를 방어하기 위해 브릿지 설정(<networkConnector>)에 decreaseNetworkConsumerPriority="true" (최신 버전 기본값) 옵션이 존재합니다.
- 동작 방식: 이 옵션이 켜지면, 원격 브로커(B)와 연결된 브릿지 컨슈머의 우선순위(Priority)를 로컬 애플리케이션 컨슈머보다 한 단계 낮게(Decrease) 평가합니다.
- 결과: A 브로커에 유입된 메시지는 무조건 로컬 컨슈머가 100% 우선적으로 처리합니다. 로컬 컨슈머가 죽거나, 처리 속도가 너무 느려서 큐에 메시지가 쌓이기 시작할 때만 비로소 브릿지가 개입하여 남는 메시지들을 B 브로커로 넘겨 부하를 분산(Load Balancing)시킵니다.
3. 멀티 컨슈머 최적화: conduitSubscriptions
B 브로커 쪽에 1개의 큐를 리스닝하는 컨슈머가 무려 10대나 붙어있다고 가정해 보겠습니다. 수요가 10배이므로, A 브로커의 브릿지는 10개의 파이프라인을 뚫고 데이터를 10번 복사해서 넘겨야 할까요?
ActiveMQ는 이러한 네트워크 대역폭 낭비를 막기 위해 conduitSubscriptions="true" (도관 구독) 옵션을 기본적으로 활성화해 둡니다.
- 동작 방식: 원격 브로커(B)에 아무리 많은 컨슈머가 붙어있어도, 브릿지는 이를 단 1개의 논리적인 거대한 '수요(Demand)'로 취합(Conduit)하여 인식합니다.
- 네트워크 최적화: A 브로커는 브릿지를 통해 메시지를 딱 한 번만 네트워크로 전송합니다. 메시지가 B 브로커에 도착하면, 그때 B 브로커가 자신의 메모리에 있는 10대의 컨슈머에게 알아서 메시지를 분배합니다. 브로커 간의 백본 네트워크 트래픽을 극단적으로 다이어트시키는 핵심 메커니즘입니다.
4. 수요 원칙의 예외: staticallyIncludedDestinations
모든 아키텍처에는 예외가 필요합니다. 수요가 없어도, 즉 B 브로커 쪽에 당장 컨슈머가 살아있지 않더라도 무조건 메시지를 B 브로커로 넘겨서 저장해 두어야 하는 특수 상황이 존재합니다. (예: 주간에만 켜지는 배치 서버가 B 브로커에 붙어있을 때)
이때는 철저한 '수요 기반 원칙(Demand-Forwarding)'을 강제로 무시하고 브릿지의 문을 항시 개방해야 합니다.
- 설정 방법: 브릿지 설정 내부에
<staticallyIncludedDestinations>태그를 열고 강제로 넘길 큐나 토픽의 이름을 명시합니다. - 효과: 이 목록에 포함된 목적지는 B 브로커 측에 접속한 컨슈머가 단 한 대도 없어도, A 브로커에 메시지가 들어오자마자 브릿지가 즉각적으로 개입하여 메시지를 B 브로커로 퍼 나릅니다. 이른바 Store-and-Forward 패턴을 인위적으로 구현할 때 사용되는 필수 옵션입니다.
5. 무한 루프 방지: networkTTL
Network of Brokers를 이중, 삼중의 Mesh 구조로 엮어놓으면, A 브로커에서 출발한 메시지가 브릿지를 타고 B 브로커로 갔다가, 수요를 찾아 다시 A 브로커의 브릿지를 타고 돌아오는 끔찍한 '무한 루프(Infinite Loop)'에 빠질 위험이 있습니다.
메시지가 브로커 사이를 핑퐁하며 CPU와 메모리를 완전히 고갈시키는 이 재앙을 막기 위해, 브릿지는 메시지를 가져갈 때 반드시 networkTTL (Time To Live) 값을 검사합니다.
- 동작 방식: 메시지가 브릿지를 한 번 통과할 때마다 메시지 내부 메타데이터의 TTL 카운트가 1씩 차감됩니다.
- 루프 차단: 기본적으로
networkTTL은 1로 설정됩니다. 즉, A 브로커에서 B 브로커로 한 번 넘어간 메시지는 TTL이 0이 되므로, B 브로커의 브릿지는 이 메시지를 다시 다른 브로커로 넘길 수 있는 권한을 영구적으로 상실합니다. 네트워크를 한 번 건넌 메시지는 반드시 해당 브로커 내에서 소비되거나 폐기되어야만 하도록 강제하여 시스템의 붕괴를 막습니다.
결론적으로 Network of Brokers의 '브릿지'는 단순한 복사기가 아니라, 로컬 처리량을 최우선으로 존중하고 네트워크 비용을 극도로 아끼도록 튜닝된 아주 예민하고 똑똑한 라우팅 에이전트입니다. decreaseNetworkConsumerPriority와 conduitSubscriptions 같은 파라미터들이 시스템 내부에서 빚어내는 역학 관계를 정확히 이해해야만, 수백 대의 브로커가 얽힌 복잡한 토폴로지에서도 메시지의 흐름을 완벽하게 통제할 수 있습니다.
'1. 개발 > 1.8. ActiveMQ' 카테고리의 다른 글
| 'decreaseNetworkConsumerPriority' 옵션의 클러스터 부하 분산 원리는? (0) | 2026.04.10 |
|---|---|
| 'Duplex Network Bridge'가 방화벽 환경에서 가지는 이점은? (0) | 2026.04.10 |
| 'maxReconnectAttempts' 설정에 따른 클라이언트 무한 루프 방지법? (0) | 2026.04.09 |
| 'priorityBackup' 옵션을 사용한 주 브로커 선호도 설정법은? (0) | 2026.04.09 |
| 'Failover Transport' 주소에서 'randomize=false' 설정의 중요성은? (0) | 2026.04.09 |