본문 바로가기
1. 개발/1.8. ActiveMQ

'suppressDuplicateQueueSubscriptions' 설정이 중복 배달을 막는 법?

by 엉짱 2026. 4. 10.
반응형

'suppressDuplicateQueueSubscriptions' 설정이 중복 배달을 막는 법?

엔터프라이즈 환경에서 단일 메시지 브로커의 한계를 극복하기 위해 여러 대의 브로커를 거미줄처럼 엮는 'Network of Brokers (NoB)' 아키텍처는 시스템의 확장성과 고가용성을 보장하는 핵심 기술입니다. 하지만 브로커의 개수가 3대 이상으로 늘어나고 서로가 양방향으로 복잡하게 얽히는 풀 메쉬(Full Mesh) 구조나 다중 경로(Multi-path) 토폴로지가 구성되는 순간, 인프라 엔지니어는 '메시지 중복 배달(Duplicate Message Delivery)'이라는 치명적인 분산 시스템의 저주와 마주하게 됩니다.

결제나 주문과 같은 크리티컬한 비즈니스 로직에서 단 하나의 메시지가 두 번 처리되는 것은 인프라 전체의 정합성을 무너뜨리는 대형 사고입니다. 이 가이드에서는 복잡한 네트워크 토폴로지에서 중복 배달이 왜 발생하는지 그 물리적 라우팅의 함정을 파헤치고, 이를 커널 레벨에서 우아하게 차단하는 suppressDuplicateQueueSubscriptions 파라미터의 아키텍처적 마법을 상세히 해부합니다.


1. 복잡한 브로커 네트워크(Mesh Topology)의 함정

Network of Brokers의 기본적인 라우팅 대원칙은 '수요 기반 전달(Demand-Forwarding)'입니다. 특정 브로커에 컨슈머(Consumer) 애플리케이션이 접속하면, 해당 브로커는 자신과 브릿지(Bridge)로 연결된 다른 브로커들에게 "나에게 메시지를 처리할 수 있는 컨슈머가 있다"라는 구독 정보(Advisory Message)를 전파합니다.

단순한 A-B 구조에서는 아무런 문제가 없습니다. 하지만 브로커 A, B, C가 삼각형 형태로 서로 모두 연결된 메쉬(Mesh) 토폴로지를 구성했다고 가정해 보겠습니다.

  • 브로커 C에 새로운 컨슈머 애플리케이션이 접속합니다.
  • 브로커 C는 자신과 직접 연결된 브로커 A와 브로커 B에게 각각 구독 정보(수요)를 방송합니다.
  • 여기서 비극이 시작됩니다. 브로커 B는 브로커 C로부터 받은 구독 정보를 바탕으로, 다시 자신과 연결된 브로커 A에게 "나를 거치면 C의 컨슈머로 갈 수 있다"며 구독 정보를 한 번 더 전파(Propagation)합니다.

2. 다중 경로(Multi-path)가 유발하는 중복 구독의 재앙

브로커 A의 입장에서 상황을 정리해 보겠습니다. 브로커 A는 분명히 브로커 C에 있는 단 한 대의 컨슈머를 바라보고 있지만, 라우팅 테이블에는 다음과 같이 동일한 컨슈머를 향하는 두 개의 가짜 수요(네트워크 구독)가 생성됩니다.

  1. 직접 경로 (Direct Path): A -> C 로 가는 네트워크 구독
  2. 우회 경로 (Indirect Path): A -> B -> C 로 가는 네트워크 구독

이 상태에서 프로듀서가 브로커 A에 메시지를 쏟아내기 시작하면, 브로커 A의 디스패치 엔진은 혼란에 빠집니다. A 브로커는 두 개의 서로 다른 컨슈머(실제로는 동일한 목적지를 향하는 두 개의 경로)가 존재한다고 착각하기 때문입니다.

결국 브로커 A는 메시지를 브로커 C로도 하나 쏘고, 브로커 B로도 하나 쏘는 최악의 판단을 내립니다. 브로커 B로 넘어간 메시지는 다시 브로커 C로 전달되며, 최종적으로 브로커 C에 붙어있던 단 하나의 컨슈머가 똑같은 메시지를 두 번 수신하게 되는 완벽한 중복 배달(Duplicate Delivery) 붕괴가 발생합니다.


3. 'suppressDuplicateQueueSubscriptions'의 필터링 원리

이러한 다중 경로 환경에서의 구독 정보 뻥튀기 현상을 원천 차단하고 단일 라우팅 파이프라인을 강제하는 최후의 안전밸브가 바로 suppressDuplicateQueueSubscriptions (중복 큐 구독 억제) 옵션입니다.

이 옵션을 true로 활성화하면, 브로커 간에 구독 정보를 주고받을 때 내부적으로 매우 정교한 ID 검증 및 경로 최적화 알고리즘이 작동하기 시작합니다.

  • 글로벌 컨슈머 ID 추적: 모든 컨슈머가 브로커에 접속할 때 부여받는 고유 식별자(Client ID 및 Session ID)를 브릿지가 전파하는 구독 정보 깊숙한 곳까지 추적하여 메타데이터화 합니다.
  • 최단 경로(Shortest Path) 선택과 억제: 브로커 A가 직접 연결된 C로부터 구독 정보를 받고, 우회 경로인 B로부터 똑같은 ID의 구독 정보를 중복으로 수신했을 때, A 브로커의 라우팅 엔진은 두 경로의 홉(Hop) 수를 비교합니다.
  • 브릿지 논리적 차단: A 브로커는 홉 수가 더 많은(경로가 더 긴) B 브로커로부터 온 네트워크 구독을 라우팅 테이블에서 강제로 삭제(Suppress)해버립니다. 즉, 오직 가장 빠르고 다이렉트한 A -> C 경로 하나만을 유효한 수요로 인정합니다.

이 메커니즘을 통해 브로커 내부에 아무리 복잡한 거미줄 토폴로지가 형성되어 있더라도, 특정 컨슈머를 향하는 경로는 논리적인 단일 스패닝 트리(Spanning Tree) 구조로 정리되며 중복 배달 경로가 커널 레벨에서 소멸하게 됩니다.


4. 인프라 적용 가이드 및 핵심 설정법

이 옵션은 activemq.xml<networkConnector> 블록 내에 선언하여 브로커 간의 브릿지 정책을 통제합니다. 복잡한 망을 구성하는 모든 브로커 쌍에 이 설정을 일관되게 부여해야 완벽한 방어선이 구축됩니다.

<networkConnectors>
    <networkConnector name="mesh-bridge-to-B" 
                      uri="static:(tcp://brokerB:61616)" 
                      suppressDuplicateQueueSubscriptions="true" />

    <networkConnector name="mesh-bridge-to-C" 
                      uri="static:(tcp://brokerC:61616)" 
                      suppressDuplicateQueueSubscriptions="true" />
</networkConnectors>

[버전 및 동작 대상의 제약]
이 옵션의 이름에 명시되어 있듯이, 이 기능은 일대일(Point-to-Point) 통신 모델인 큐(Queue) 목적지에만 제한적으로 적용됩니다. 일대다(Publish-Subscribe) 브로드캐스팅 모델인 토픽(Topic) 통신에서는 다중 경로로 인한 중복을 다른 방식(예: suppressDuplicateTopicSubscriptions)으로 제어해야 하므로 아키텍처 설계 시 통신 모델을 명확히 구분해야 합니다.


5. 운영 시 주의사항 및 아키텍처 최적화 (Best Practices)

이 옵션은 중복 배달을 막는 훌륭한 스위치지만, 인프라의 라우팅 가시성(Visibility)을 일시적으로 제한할 수 있으므로 다음의 최적화 파라미터들과 짝을 이루어 사용해야 합니다.

  1. conduitSubscriptions="true"와의 시너지: suppressDuplicateQueueSubscriptions가 '동일한 컨슈머'의 중복 경로를 필터링한다면, conduitSubscriptions는 '여러 대의 컨슈머'를 하나의 굵은 파이프라인으로 압축해 줍니다. 이 두 옵션을 동시에 활성화해야만 다중 경로와 다중 컨슈머가 혼재하는 복잡한 환경에서 네트워크 백본의 대역폭을 가장 효율적으로 아낄 수 있습니다.
  2. decreaseNetworkConsumerPriority="true" 병행: 다중 경로의 억제와 별개로, 메시지가 굳이 네트워크를 건너지 않고 로컬 브로커 내에서 최대한 소비되도록 우선순위 강등 옵션을 함께 켜두어야 불필요한 브릿지 통신 자체를 최소화할 수 있습니다.
  3. Hub and Spoke 토폴로지에서의 불필요성: 만약 3대 이상의 브로커가 링(Ring)이나 메쉬(Mesh) 구조가 아니라, 철저하게 중앙 브로커(Hub) 하나에 여러 지사 브로커(Spoke)가 1:1로만 연결된 구조라면 다중 경로 자체가 물리적으로 발생하지 않습니다. 이때는 이 옵션의 필터링 연산 자체가 CPU 오버헤드가 될 수 있으므로, 시스템의 토폴로지가 루프(Loop)를 형성하는 구조인지 사전에 명확히 진단하고 도입을 결정해야 합니다.

결론적으로 'suppressDuplicateQueueSubscriptions'는 거대한 분산 시스템에서 메시지의 흐름을 단일 차선으로 정렬해 주는 정교한 교통 통제 시스템입니다. 인프라가 메쉬망 형태로 진화할 때 필연적으로 겪게 되는 라우팅의 환영(Phantom Routing)을 이 옵션을 통해 깨끗하게 제거하고, 어떤 경로로 통신하든 정확히 한 번만 배달되는(Exactly-once) 무결점의 메시징 백본을 완성하시기 바랍니다.

반응형