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

'Producer Flow Control' 발생 시 로그에 찍히는 특정 메시지 패턴은?

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

'Producer Flow Control' 발생 시 로그에 찍히는 특정 메시지 패턴은?

엔터프라이즈 환경에서 메시지 브로커(ActiveMQ, Artemis 등)를 운영하다 보면, 어느 순간 평화롭던 프로듀서(Producer) 애플리케이션들이 약속이나 한 듯 메시지 전송을 멈추고 얼어붙는(Hang) 현상을 겪게 됩니다. 시스템 모니터링 대시보드에는 CPU나 메모리의 이상 징후가 명확하게 보이지 않는데도 트래픽 처리가 완전히 마비되는 이 기이한 현상의 배후에는, 브로커가 자신을 보호하기 위해 발동한 '프로듀서 흐름 제어(Producer Flow Control)' 메커니즘이 존재합니다.

브로커가 프로듀서의 목줄을 쥐고 전송을 강제로 차단하기 시작할 때, 시스템 관리자가 가장 먼저 확인해야 할 유일하고 확실한 단서는 브로커의 백엔드 로그(Log) 파일에 숨어 있습니다. 이 가이드에서는 Producer Flow Control이 발동되는 정확한 순간 브로커 로그에 기록되는 특정 메시지 패턴들과, 이를 해석하여 즉각적인 트러블슈팅으로 연결하는 방법을 상세히 해부합니다.


1. Producer Flow Control의 발동 조건

로그 패턴을 분석하기 전에, 브로커가 왜 이러한 제어 메커니즘을 가동하는지 근본적인 이유를 이해해야 합니다.

메시지 브로커는 컨슈머(Consumer)가 메시지를 가져가는 속도보다 프로듀서가 메시지를 밀어 넣는 속도가 압도적으로 빠를 때 메모리 고갈(Out of Memory)의 위험에 처합니다. 브로커는 설정 파일(activemq.xml 또는 broker.xml)에 지정된 메모리 사용량 한계치(Memory Usage Limit)에 도달하면, OOM으로 죽는 대신 큐(Queue)로 들어오는 입구를 틀어막는 결단을 내립니다.

입구가 막히면 메시지를 전송하려던 클라이언트의 스레드는 브로커로부터 승인(ACK)을 받지 못한 채 무한정 대기(Blocking) 상태에 빠지게 되며, 이때 브로커는 자신이 프로듀서를 차단했음을 알리는 강력한 경고 로그를 출력합니다.


2. ActiveMQ Classic 환경의 특정 로그 패턴

ActiveMQ Classic 버전을 운영 중이라면, 브로커의 메모리나 디스크 한계에 도달했을 때 activemq.log 파일에 다음과 같은 매우 명시적이고 특징적인 INFO 또는 WARN 레벨의 로그가 도배되기 시작합니다.

핵심 식별 키워드: "Usage Manager memory limit reached"

INFO | Usage Manager memory limit reached on queue://[큐 이름]. Producers will be blocked to prevent flooding.

INFO | Usage Manager memory limit reached. Stopping producer ([프로듀서 ID]) to prevent flooding queue://[큐 이름]. See http://activemq.apache.org/producer-flow-control.html for more info (blocking for: [대기 시간]s)

로그 패턴의 의미 해석:

  • Usage Manager: ActiveMQ 내부에서 시스템의 메모리, 임시 저장소(Temp Store), 주 저장소(Store)의 사용량을 모니터링하고 임계치를 통제하는 핵심 컴포넌트입니다.
  • memory limit reached: 특정 목적지(큐나 토픽)에 할당된 메모리 한계(기본값 통상 1MB ~ 64MB) 또는 브로커 전체 시스템 메모리 한계(systemUsage)의 100퍼센트를 꽉 채웠다는 뜻입니다.
  • Producers will be blocked: 브로커가 클라이언트의 TCP 소켓 수신 버퍼를 읽는 것을 멈추었으며, 이로 인해 클라이언트 애플리케이션의 send() 메서드가 멈춰 섰음(블로킹)을 의미합니다.

3. ActiveMQ Artemis 환경의 특정 로그 패턴

차세대 아키텍처인 ActiveMQ Artemis는 큐의 메모리가 가득 찼을 때 어떻게 행동할지를 address-full-policy라는 설정으로 세밀하게 제어합니다. 이 설정이 BLOCK으로 되어 있을 때(메모리 초과 시 프로듀서 차단), artemis.log에는 다음과 같은 에러 코드 형태의 명확한 경고 로그가 기록됩니다.

핵심 식별 키워드: "AMQ222183" 및 "Blocking message production"

WARN [org.apache.activemq.artemis.core.server] AMQ222183: Blocking message production on address [주소 이름]; size is currently [현재 바이트 수] bytes; max-size-bytes is [설정된 최대 바이트 수] bytes; global-size is [전체 바이트 수] bytes

WARN [org.apache.activemq.artemis.core.server] AMQ222039: Address [주소 이름] is full, blocking producer...

로그 패턴의 의미 해석:

  • AMQ222183: Artemis가 상태 이상을 알릴 때 사용하는 고유한 경고 코드입니다. 모니터링 시스템(예: Datadog, ELK 스택)에서 알림 규칙(Alert Rule)을 설정할 때 이 코드를 직접 타겟팅하는 것이 가장 효율적입니다.
  • size is currently [X] bytes: 현재 해당 주소(Address)에 쌓여있는 메시지들의 논리적 메모리 크기의 총합을 친절하게 알려줍니다.
  • max-size-bytes is [Y] bytes: 브로커 설정 파일에 관리자가 제한해 둔 최대 메모리 허용치입니다. 현재 바이트 수가 이 값을 초과하는 순간 바로 이 경고 로그가 출력되며 시스템이 멈춥니다.

4. 추가적인 파생 로그 패턴: 시스템 전체 한계 도달

개별 큐의 문제가 아니라, 브로커 서버 전체의 리소스가 고갈되었을 때도 프로듀서 흐름 제어가 발동합니다. 이때는 위와는 약간 다른 형태의 경고가 출력됩니다.

  • Temp Store 한계 초과 (비영속 메시지 폭주 시):

    INFO | Usage Manager temp limit reached. Stopping producer...
    비영속성(Non-persistent) 메시지들을 메모리에서 디스크의 임시 폴더로 내보내려 했으나, 브로커 시스템의 남은 디스크 용량조차 설정된 한계(tempUsage)에 도달했을 때 발생합니다.

  • Global Memory 한계 초과 (Artemis):

    AMQ222210: Free memory is at [X] bytes. There is a danger of OutOfMemoryError. Blocking all producers.
    개별 큐의 문제가 아니라 JVM 전체 힙 메모리의 절대적인 여유 공간이 부족해졌을 때 브로커가 취하는 최후의 방어선입니다. 이 로그가 찍히면 특정 큐가 아니라 브로커에 연결된 모든 프로듀서의 통신이 전면 차단됩니다.


5. 로그 발견 시 즉각적인 트러블슈팅 및 아키텍처 조치

이러한 로그 패턴이 관측되었다는 것은 서비스 장애가 이미 시작되었음을 의미합니다. 즉각적으로 다음의 3단계 조치를 취해야 합니다.

A. 긴급 조치: 컨슈머(Consumer) 스케일 아웃
입구가 막힌 이유는 출구가 막혔기 때문입니다. 메시지를 처리하는 컨슈머 애플리케이션에 병목(DB 락, 외부 API 지연 등)이 발생하지 않았는지 확인하고, 컨슈머의 인스턴스 수나 동시 처리 스레드(Concurrent Consumers)를 즉시 늘려 큐에 적체된 메시지를 빠르게 비워내야 합니다. 메모리 공간이 확보되는 순간 브로커는 차단을 해제하고 프로듀서 스레드는 다시 정상 동작합니다.

B. 예방 조치: Exception 투척 방식으로의 전환 (Fast Fail)
무한정 블로킹되는 상태는 클라이언트의 스레드 풀(Thread Pool)을 고갈시켜 장애를 다른 마이크로서비스로 전파(Cascading Failure)시킵니다.
이를 막으려면 ActiveMQ 연결 옵션에 sendFailIfNoSpace=true를 설정하십시오. 이 옵션을 켜면, 브로커 메모리가 꽉 찼을 때 클라이언트 스레드를 대기시키지 않고 즉각적으로 javax.jms.ResourceAllocationException을 던집니다. 클라이언트는 이 예외를 캐치하여 즉시 에러 처리를 하거나 지연 전송을 시도할 수 있어 스레드 고갈을 막을 수 있습니다.

C. 아키텍처 조치: Paging 모드로의 전환
본질적으로 트래픽 스파이크가 잦은 비즈니스라면 address-full-policyBLOCK이 아닌 PAGE로 변경해야 합니다. 메모리가 꽉 차더라도 프로듀서를 차단하지 않고 들어오는 메시지를 즉시 디스크의 페이징 파일로 우회시켜 끝까지 수용하도록 아키텍처의 패러다임을 전환해야 인프라의 유연성을 확보할 수 있습니다.

요약하자면, memory limit reached 또는 Blocking message production 이라는 로그는 브로커가 인프라 붕괴를 막기 위해 스스로 내지르는 비명과도 같습니다. 로그 수집기(Logstash, Fluentd)에 해당 패턴을 감지하는 정규식을 등록하고, 로그가 찍히는 즉시 알림이 발생하도록 모니터링 체계를 고도화하시기 바랍니다.

반응형