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

'Filter'와 'Divert'를 조합한 정교한 메시지 라우팅 설계법은?

by 엉짱 2026. 3. 19.
반응형

'Filter'와 'Divert'를 조합한 정교한 메시지 라우팅 설계법은?

엔터프라이즈 아키텍처에서 메시지 브로커를 단순한 데이터 전달 통로 이상으로 활용하려면, 브로커 내부의 라우팅 엔진을 적극적으로 다루어야 합니다. ActiveMQ Artemis가 제공하는 'Filter(필터)'와 'Divert(다이버트)' 기능을 결합하면, 클라이언트 애플리케이션의 소스 코드를 수정하지 않고도 브로커 메모리 상에서 극도로 정교한 조건부 메시지 라우팅(Conditional Routing) 파이프라인을 구축할 수 있습니다.

1. 두 기능의 역할 분담과 결합 시너지

  • Filter (조건 판별자): 메시지의 헤더(표준 속성 및 사용자 정의 속성)를 SQL-92 문법으로 평가하여 조건에 부합하는지 판별합니다.
  • Divert (경로 변경자): 메시지의 본래 목적지(Address)를 가로채어 다른 목적지(Forwarding Address)로 흐름을 틀어버리거나(Exclusive), 복제본을 흘려보냅니다(Non-Exclusive).

이 둘을 결합하면 "특정 조건을 만족하는 메시지만 선택적으로 가로채어 다른 곳으로 보낸다"는 지능적인 라우팅 규칙이 완성됩니다. 생산자는 모든 데이터를 하나의 글로벌 주소로 던지기만 하면 되고, 복잡한 분기 처리는 온전히 브로커의 인프라 설정으로 이관됩니다.

2. 조건부 트래픽 격리 (Filter + Exclusive Divert)

특정 비즈니스 조건에 맞는 트래픽만 완전히 분리하여 별도의 전용 큐에서 처리해야 할 때 사용합니다. 원본 주소로 들어온 메시지 중 필터 조건에 맞는 메시지는 지정된 새 주소로만 이동하며, 기존 큐로는 전달되지 않습니다.

활용 시나리오: 글로벌 서비스의 지역별 데이터 분기
생산자가 전 세계의 센서 데이터를 telemetry.global이라는 단일 주소로 전송합니다. 하지만 유럽 연합(EU)의 GDPR 규제로 인해, 헤더에 region = 'EU'가 찍힌 데이터는 무조건 유럽 지역 내의 별도 스토리지 큐(telemetry.eu.strict)로 격리되어야 합니다.

이때 telemetry.global 주소에 필터를 단 Exclusive Divert를 설정하면, 아시아나 미주 지역 데이터는 기존의 일반 큐로 정상적으로 흘러가고, 오직 EU 데이터만 브로커 내부에서 방향을 틀어 전용 큐로 안전하게 격리됩니다. 클라이언트의 배포 없이 규제 요건을 즉각적으로 충족할 수 있습니다.

3. 조건부 데이터 복제 (Filter + Non-Exclusive Divert)

메인 비즈니스 흐름을 전혀 방해하지 않으면서, 특정 조건을 만족하는 메시지만 복사하여 모니터링이나 추가 처리를 수행할 때 활용합니다.

활용 시나리오: 고액 결제 건 실시간 모니터링 (Wire Tap)
결제 처리 큐(payment.requests)에는 수많은 소액/고액 결제 트랜잭션이 인입됩니다. 메인 결제 워커들은 이 큐를 바라보고 바쁘게 결제를 승인합니다. 그런데 사기 탐지(FDS) 팀에서 "결제 금액이 100만 원 이상인 건만 실시간으로 복사해서 분석 시스템으로 보내달라"고 요청합니다.

이 경우 payment.requests 주소에 amount >= 1000000 필터를 적용한 Non-Exclusive Divert를 설정합니다. 메인 결제 시스템은 평소처럼 모든 결제를 처리하지만, 100만 원 이상의 결제 메시지가 들어오는 찰나의 순간에 브로커가 이를 복제하여 사기 탐지 전용 큐(payment.fraud.detect)로 조용히 밀어 넣습니다.

4. Artemis 설정(broker.xml) 구현 예시

위에서 설명한 두 가지 시나리오를 broker.xml 파일의 <diverts> 블록에 어떻게 정의하는지 보여주는 설정 코드입니다.

<diverts>
   <divert name="eu-telemetry-isolation">
      <address>telemetry.global</address>
      <forwarding-address>telemetry.eu.strict</forwarding-address>
      <filter string="region = 'EU'"/>
      <exclusive>true</exclusive>
   </divert>

   <divert name="high-value-payment-audit">
      <address>payment.requests</address>
      <forwarding-address>payment.fraud.detect</forwarding-address>
      <filter string="amount >= 1000000"/>
      <exclusive>false</exclusive>
   </divert>
</diverts>

5. 아키텍처 설계 시 주의사항 및 최적화 전략

Filter와 Divert의 결합은 매우 강력한 무기지만, 잘못 사용하면 브로커 성능의 무덤이 될 수 있습니다. 설계 시 다음 원칙을 반드시 준수해야 합니다.

  • CPU 연산 병목 주의: 브로커에 인입되는 모든 메시지는 Divert의 Filter 평가를 거쳐야 합니다. 필터 조건에 LIKE 문을 사용한 복잡한 문자열 패턴 매칭이 포함되거나, 평가해야 할 조건(AND/OR 묶음)이 너무 길어지면 브로커의 메인 디스패치 스레드 CPU 사용률이 폭증합니다. 필터는 가급적 동등 비교(=, IN) 위주로 단순하게 유지해야 합니다.
  • 본문(Payload) 의존 불가: Filter는 메시지의 헤더(JMS Properties)만 읽을 수 있습니다. JSON이나 XML 등 메시지 본문 내용에 따라 라우팅을 분기해야 한다면, 브로커 설정의 Transformer를 이용하거나 외부 라우터(Apache Camel 등)를 사용해야 합니다.
  • 루프(Loop) 차단: 라우팅 규칙이 복잡해질수록 A 주소에서 B 주소로, B 주소에서 다시 A 주소로 Divert되는 순환 참조(Circular Routing) 위험이 커집니다. 브로커는 메시지 헤더 내부 추적을 통해 일부 루프를 차단하려 시도하지만, 최초 설계 시부터 토폴로지가 단방향 흐름을 갖도록 엄격하게 문서화하고 통제해야 합니다.
  • 권한 및 보안: Divert 설정은 오직 브로커 관리자만이 broker.xml이나 JMX/Jolokia 관리 API를 통해 제어할 수 있습니다. 개발자가 임의로 라우팅을 변경하지 못하도록 인프라스트럭처로서의 관리 권한을 명확히 분리해야 합니다.

이러한 설계 원칙을 지킨다면, Filter와 Divert의 조합은 시스템 간 결합도를 최소화하면서도 비즈니스 요구사항의 변화에 즉각적으로 대응할 수 있는 가장 우아하고 빠른 메시징 아키텍처의 핵심 뼈대가 될 것입니다.

반응형