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

서버 측 큐 브라우징(Queue Browsing)과 컨슈밍의 차이는?

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

서버 측 큐 브라우징(Queue Browsing)과 컨슈밍의 차이는?

메시지 지향 미들웨어(MOM) 환경에서 큐(Queue)에 적재된 데이터를 다루는 방식은 크게 두 가지로 나뉩니다. 하나는 비즈니스 로직 처리를 위해 메시지를 꺼내어 없애는 컨슈밍(Consuming)이며, 다른 하나는 큐의 상태를 모니터링하기 위해 메시지를 들여다보기만 하는 큐 브라우징(Queue Browsing)입니다.

이 두 가지 접근 방식은 내부 동작 메커니즘, 브로커에 미치는 리소스 부하, 그리고 트랜잭션 처리 관점에서 완전히 다른 철학을 가지고 있습니다. 성공적인 메시징 아키텍처 운영을 위해 반드시 구분해야 할 이 두 개념의 차이점과 실무 적용 시 주의사항을 상세히 분석합니다.


1. 컨슈밍(Consuming): 파괴적 읽기 (Destructive Read)

컨슈밍은 메시지 브로커의 존재 이유이자 가장 기본적인 데이터 처리 방식입니다. 클라이언트(Consumer)가 큐에 연결하여 메시지를 수신하고 처리를 완료하면, 해당 메시지는 큐에서 영구적으로 삭제됩니다.

  • 동작 원리:
  1. 브로커는 큐의 맨 앞(Head)에 있는 메시지를 컨슈머에게 전달(Deliver)합니다.
  2. 컨슈머는 비즈니스 로직(예: DB 저장, 알림 발송 등)을 수행합니다.
  3. 처리가 성공하면 컨슈머는 브로커에게 수신 확인 응답(Acknowledge, ACK)을 보냅니다.
  4. ACK를 받은 브로커는 메모리 및 디스크(KahaDB 등 영속성 저장소)에서 해당 메시지를 완전히 삭제(Remove)합니다.
  • 핵심 특징:
  • 상태 변경: 큐의 상태(메시지 개수, 큐의 깊이)를 직접적으로 변화시킵니다.
  • 독점성: 한 번 특정 컨슈머에게 전달되어 성공적으로 처리된 메시지는 다른 컨슈머가 다시 읽을 수 없습니다. (단, 메시지 그룹이나 특정 라우팅 기법 제외)
  • 트랜잭션 연동: 로컬 트랜잭션이나 분산 트랜잭션(XA)과 강하게 결합되어, 비즈니스 로직 실패 시 메시지를 롤백(Rollback)하여 재처리(Redelivery) 큐에 반환하는 등 엄격한 정합성을 보장합니다.
  • 사용 목적: 실제 비즈니스 데이터를 처리하고 애플리케이션 간의 비동기 워크플로우를 진행하기 위한 필수 메커니즘입니다.

2. 큐 브라우징(Queue Browsing): 비파괴적 읽기 (Non-Destructive Read)

큐 브라우징은 메시지를 처리하기 위해서가 아니라, 현재 큐에 어떤 데이터가 쌓여 있는지 '관찰(Inspect)'하기 위해 고안된 기능입니다. 진열장의 유리를 통해 상품을 구경만 하고 사가지는 않는 것과 같습니다.

  • 동작 원리:
    JMS(Java Message Service) 스펙에서는 이를 위해 QueueBrowser 인터페이스를 제공합니다.
  1. 클라이언트가 특정 큐에 대한 QueueBrowser 인스턴스를 생성합니다.
  2. 브로커는 현재 큐에 적재된 메시지들의 스냅샷(Snapshot)을 캡처하여 클라이언트에게 열거형(Enumeration) 형태로 제공합니다.
  3. 클라이언트는 메시지의 헤더와 페이로드를 읽어 화면에 출력하거나 로깅합니다.
  4. 이 과정에서 ACK는 발생하지 않으며, 브로커는 메시지를 삭제하지 않습니다.
  • 핵심 특징:
  • 상태 보존: 브라우징을 아무리 많이 수행해도 큐에 쌓인 메시지의 개수나 순서는 전혀 변하지 않습니다.
  • 스냅샷의 한계: 브라우저가 메시지 목록을 읽어오는 그 찰나의 순간에도, 다른 실제 활성 컨슈머(Active Consumer)가 해당 메시지를 소비하여 지워버릴 수 있습니다. 따라서 브라우저가 반환한 데이터는 '조회 시점의 과거 상태'일 뿐, 현재 큐의 완벽한 실시간 상태를 보장하지는 않습니다.
  • 사용 목적: 관리자 콘솔(Admin UI)에서 큐에 쌓인 메시지 내용을 확인하거나, 특정 조건에 걸려 처리되지 못하고 쌓여있는 병목 메시지(Stuck Message)를 디버깅 및 감사(Auditing)할 때 사용됩니다.

3. 핵심 차이점 비교 요약

비교 항목 컨슈밍 (Consuming) 큐 브라우징 (Queue Browsing)
데이터 처리 방식 파괴적 (읽은 후 삭제됨) 비파괴적 (읽은 후 그대로 유지됨)
ACK(수신 확인) 필요 여부 필수 (ACK 수신 시 메시지 삭제) 불필요 (ACK 개념 없음)
JMS API 인터페이스 MessageConsumer QueueBrowser
큐 상태 변경 여부 큐의 Depth(크기)가 감소함 큐의 상태에 아무런 영향을 주지 않음
병행 처리(Concurrency) 다른 컨슈머와 메시지를 경쟁하여 나누어 가짐 다른 컨슈머의 메시지 소비를 방해하지 않음
주요 활용 사례 비즈니스 로직 수행, 이벤트 파이프라인 관리자 모니터링, 장애 디버깅, 로그 감사

4. 아키텍처 및 성능 상의 주의사항 (Anti-Patterns)

큐 브라우징이 메시지를 건드리지 않는다고 해서 "시스템 부하가 없는 가벼운 작업"이라고 착각해서는 안 됩니다. 실무 환경에서 브라우징 기능의 오남용은 심각한 브로커 장애를 유발할 수 있습니다.

A. 딥 큐(Deep Queue) 브라우징의 덫

큐에 수십만 개의 메시지가 쌓여 있는 상태(Deep Queue)에서 전체 큐 브라우징을 시도하면, 브로커는 디스크(KahaDB 등)에 페이징 아웃(Paged out)되어 있던 엄청난 양의 메시지를 다시 JVM 힙 메모리로 끌어올려야(Paging in) 합니다. 이는 극심한 디스크 I/O 병목과 브로커 서버의 OOM(Out of Memory), 그리고 Stop-the-World GC(가비지 컬렉션) 멈춤 현상을 초래하여 실제 비즈니스 메시지 처리를 전면 중단시킬 수 있습니다.

B. 브라우징 시 셀렉터(Selector) 연산 부하

QueueBrowser를 생성할 때 특정 조건의 메시지만 보기 위해 메시지 셀렉터(예: session.createBrowser(queue, "JMSPriority > 5"))를 적용할 수 있습니다. 데이터베이스의 인덱스가 없는 메시지 큐 특성상, 브로커는 조건에 맞는 메시지를 찾기 위해 큐 전체를 순차적으로 스캔(Full Scan)하며 헤더를 파싱해야 하므로 CPU 자원을 심하게 소모합니다.

C. 안전한 모니터링 설계 가이드

안정적인 시스템 운영을 위해 브라우징 기능은 다음과 같이 제한적으로 설계되어야 합니다.

  1. 제한된 스캔: 관리자 UI에서 브라우징 기능을 제공할 때는 전체 조회를 금지하고, 반드시 한 번에 조회할 수 있는 최대 메시지 개수(예: 상위 50개)를 엄격히 제한(Pagination/Limit)해야 합니다.
  2. 모니터링 토픽 분리: 주기적이고 자동화된 모니터링이 필요하다면 큐 브라우저로 큐를 긁어오는(Polling) 방식 대신, 앞서 다룬 브로커의 Advisory Topic 기능이나 JMX 메트릭(Metric) 연동을 활용하는 것이 브로커 리소스 보호 측면에서 훨씬 안전한 아키텍처입니다.
반응형