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

만료된 메시지(Expired)를 추적하기 위한 감사(Audit) 로그 설정은?

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

만료된 메시지(Expired)를 추적하기 위한 감사(Audit) 로그 설정은?

메시지 지향 미들웨어(MOM) 환경에서 메시지 생산자(Producer)는 각 메시지에 수명(Time-To-Live, TTL)을 부여할 수 있습니다. 큐(Queue)에 적재된 메시지가 컨슈머(Consumer)에 의해 소비되기 전에 설정된 TTL을 초과하면, 브로커는 해당 메시지를 유효하지 않은 것으로 간주하고 큐에서 제거합니다.

문제는 이렇게 만료되어 사라진 메시지들이 시스템에서 완전히 증발해 버리면, 추후 "왜 데이터가 목적지에 도달하지 못했는가?"를 디버깅하거나 비즈니스 감사(Audit)를 수행할 때 심각한 가시성(Observability) 결여를 초래한다는 점입니다.

따라서 엔터프라이즈 환경에서는 만료된 메시지가 조용히 사라지지 않도록 별도의 지정된 공간으로 격리하고, 이를 파일이나 중앙 집중식 로그 시스템에 명확한 감사 로그(Audit Log)로 남기는 아키텍처 구성이 필수적입니다. ActiveMQ Artemis와 Classic 버전에서 이 추적 파이프라인을 구축하는 구체적인 설정 가이드를 상세히 해부합니다.


1. ActiveMQ Artemis: Expiry Address와 Audit Log 설정

차세대 브로커인 Artemis는 메시지 만료와 로깅 처리를 매우 명확한 계층으로 분리하여 제공합니다. 만료된 메시지를 즉시 삭제하지 않고 지정된 expiry-address로 안전하게 라우팅한 뒤, 해당 주소의 변동 사항을 로깅 프레임워크와 연동하는 방식입니다.

A. Expiry Address (만료 주소) 매핑 설정

먼저 broker.xml 파일의 <address-settings> 블록을 수정하여, 특정 주소나 큐에서 메시지가 만료되었을 때 이동할 종착지를 지정합니다.

<address-settings>
   <address-setting match="business.orders.#">
      <expiry-address>audit.expired.orders</expiry-address>
      <expiry-delay>1000</expiry-delay>
   </address-setting>

   <address-setting match="audit.expired.orders">
      <max-size-bytes>100000000</max-size-bytes>
   </address-setting>
</address-settings>

위 설정을 통해 business.orders.# 패턴을 가진 큐에서 TTL이 지난 메시지는 삭제되지 않고 audit.expired.orders라는 특수한 주소로 원본 데이터(페이로드 및 헤더)를 유지한 채 이동합니다. 이때 브로커는 메시지 헤더에 _AMQ_ACTUAL_EXPIRY (실제 만료 시간) 등의 메타데이터를 자동으로 추가하여 추적을 돕습니다.

B. Audit Logging (감사 로깅) 활성화

Artemis는 브로커 내부에서 발생하는 관리 및 운영 이벤트를 파일로 기록하는 Audit Logger 기능을 내장하고 있습니다. 메시지 레벨의 로깅을 활성화하려면 로깅 설정 파일(logging.properties 또는 log4j2.xml, 버전에 따라 상이)을 수정해야 합니다.

  • Message Audit Logger 활성화:
    Artemis는 일반적인 브로커 로그 외에 메시지 흐름을 추적하는 org.apache.activemq.audit.message 로거를 제공합니다.
# logging.properties 예시
logger.org.apache.activemq.audit.message.level=INFO
logger.org.apache.activemq.audit.message.handlers=AUDIT_FILE

handler.AUDIT_FILE=org.jboss.logmanager.handlers.PeriodicRotatingFileHandler
handler.AUDIT_FILE.level=INFO
handler.AUDIT_FILE.fileName=${artemis.instance}/log/audit-message.log
handler.AUDIT_FILE.append=true
handler.AUDIT_FILE.formatter=AUDIT_PATTERN

만료된 메시지 전용 컨슈머(또는 Camel 라우트)를 audit.expired.orders 큐에 연결하여 메시지를 읽어갈 때, 이 Audit 로그에 "누가, 언제, 어떤 만료된 메시지를 조회/처리했는지"에 대한 기록이 명확하게 남게 됩니다.


2. ActiveMQ Classic: Dead Letter 설정과 Broker Plugin 활용

ActiveMQ 5.x (Classic) 환경에서는 만료된 메시지가 기본적으로 ActiveMQ.DLQ (Dead Letter Queue)로 이동하는 로직을 활용하며, 별도의 플러그인을 통해 로깅을 강화할 수 있습니다.

A. Expired 메시지 DLQ 라우팅 명시

activemq.xml 파일에서 목적지 정책(destinationPolicy)을 설정할 때, processExpired="true" 속성을 활성화하여 만료된 메시지가 소멸되지 않고 DLQ로 향하도록 강제해야 합니다.

<destinationPolicy>
   <policyMap>
      <policyEntries>
         <policyEntry queue=">">
            <deadLetterStrategy>
               <sharedDeadLetterStrategy processExpired="true" expiration="0"/>
            </deadLetterStrategy>
         </policyEntry>
      </policyEntries>
   </policyMap>
</destinationPolicy>

B. Logging Broker Plugin을 통한 즉각적인 로깅

DLQ에 쌓이는 것을 넘어, 메시지가 만료되어 브로커에 의해 처리되는 바로 그 시점에 로그 파일(Log4j)에 기록을 남기고 싶다면 <loggingBrokerPlugin>을 파이프라인에 추가합니다.

<plugins>
   <loggingBrokerPlugin logAll="false" logMessageEvents="true" logConnectionEvents="false"/>
</plugins>

이 플러그인을 활성화하고 log4j.properties 파일에서 org.apache.activemq.broker.util.LoggingBrokerPlugin 로거의 레벨을 INFODEBUG로 설정하면, 메시지가 만료(Discarding expired message)되는 시점의 상세한 메타데이터(Message ID, Destination, Expiration Time)가 애플리케이션 로그에 파일 형태로 적재됩니다.


3. 감사 로그 인프라 구축 시 아키텍처 고려사항

브로커 설정 파일에서 로깅 및 라우팅을 구성한 후, 이를 엔터프라이즈급 감사 시스템으로 승격시키기 위해 다음 세 가지 방안을 시스템 아키텍처에 반영해야 합니다.

  1. 전용 추적(Tracing) 워커 구성:
    브로커의 파일 로그(audit-message.log)에만 의존하는 것은 검색과 통계 분석에 한계가 있습니다. 가장 권장되는 방식은 expiry-address (또는 DLQ)에만 단독으로 연결되는 경량화된 컨슈머 애플리케이션(예: Spring Boot 워커)을 별도로 띄우는 것입니다. 이 워커는 메시지를 꺼내어 페이로드와 JMSMessageID, _AMQ_ACTUAL_EXPIRY 헤더 값을 파싱한 뒤, Elasticsearch나 Splunk와 같은 중앙 집중식 로그 수집 시스템으로 HTTP API를 통해 쏘아주는 역할만 전담합니다.
  2. 페이로드(Payload) 로깅 제한:
    만료된 메시지의 크기가 수 MB에 달할 경우, 이를 통째로 파일 로그에 남기거나 DB에 인서트하면 심각한 디스크 I/O 병목과 스토리지 비용 상승이 발생합니다. 감사 로그에는 반드시 식별이 가능한 헤더(Header) 메타데이터와 상관관계 ID(Correlation ID)만 남기고, 무거운 페이로드 본문은 버리거나 저렴한 오브젝트 스토리지(S3 등)에 압축하여 백업하는 방안을 채택해야 합니다.
  3. 메시지 폭주(Flood) 대비:
    특정 장애 상황에서 수십만 개의 메시지가 동시에 만료될 수 있습니다. 이때 Expiry Queue나 로그 파일에 쓰기 작업이 집중되면서 브로커의 메인 디스패치 스레드가 지연되는 현상을 막아야 합니다. Expiry Queue 자체에 대해서는 페이징(Paging) 설정을 넉넉하게 부여하여 브로커 힙 메모리 공간을 침범하지 않도록 격리 수준을 높여두는 것이 필수적입니다.

이러한 단계적인 라우팅과 로깅 파이프라인 구성을 통해, 단 하나의 만료된 메시지도 추적 범위를 벗어나지 않는 견고하고 투명한 메시징 인프라를 완성할 수 있습니다.

반응형