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

'redistribution-delay' 수치 결정 시 고려해야 할 네트워크 상황?

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

'redistribution-delay' 수치 결정 시 고려해야 할 네트워크 상황?

메시지 브로커(ActiveMQ Artemis 등)를 클러스터로 묶어 운영하는 환경에서, 특정 브로커에 연결되어 있던 마지막 컨슈머(Consumer)가 사라졌을 때 남겨진 메시지들을 다른 브로커로 구출해 내는 '메시지 재분배(Message Redistribution)' 기능은 시스템의 가용성을 지키는 핵심 방어선입니다.

이때 브로커가 컨슈머의 부재를 인지한 직후, 즉각적으로 메시지를 옮길지 아니면 잠시 기다려 줄지를 결정하는 파라미터가 바로 redistribution-delay입니다. 이 수치(밀리초 단위의 대기 시간)를 단순히 감에 의존하여 설정하면, 트래픽 폭주 시 인프라 전체가 마비되는 대형 장애를 겪을 수 있습니다.

본 가이드에서는 이 대기 시간 수치를 결정할 때 아키텍트가 반드시 점검하고 고려해야 하는 4가지 치명적인 네트워크 및 인프라 상황을 상세히 해부합니다.


1. 네트워크 플래핑(Network Flapping)과 스위치 순단 현상

가장 먼저 고려해야 할 상황은 물리적 혹은 논리적 네트워크 장비의 불안정성입니다.

데이터센터 내부이거나 클라우드 환경이거나 관계없이, 라우터나 L4/L7 스위치의 라우팅 테이블이 갱신되거나 일시적인 대역폭 병목이 발생하면 TCP 연결이 0.5초에서 1초가량 짧게 끊어졌다가 다시 붙는 '네트워크 순단(Flapping)' 현상이 빈번하게 일어납니다.

  • 재앙의 시나리오: 만약 redistribution-delay를 0이나 1000(1초) 이하의 너무 짧은 값으로 설정했다면 어떨까요? 네트워크 스위치가 아주 잠깐 깜빡인 것뿐인데, 브로커는 컨슈머가 완전히 죽었다고 판단하고 수만 건의 메시지를 다른 노드로 퍼 나르기 시작합니다. 하지만 1초 뒤 컨슈머가 네트워크를 회복하고 다시 접속하면, 메시지들은 원래 자리로 돌아오기 위해 다시 네트워크를 타게 됩니다.
  • 고려 사항: 인프라 내부의 평균적인 네트워크 순단 복구 시간을 모니터링해야 합니다. 일반적인 스위치 절체 시간이나 방화벽 세션 타임아웃 갱신에 걸리는 시간보다 이 대기 시간을 길게 주어야, 브로커가 네트워크의 가벼운 기침에 과민 반응하는 것을 막을 수 있습니다.

2. 클라이언트 애플리케이션의 '재연결(Reconnect) 정책'

브로커의 대기 시간은 반드시 클라이언트 애플리케이션(컨슈머) 쪽에 설정된 '페일오버(Failover) 재연결 시간'과 완벽한 짝을 이루어야 합니다.

  • 설정의 엇박자: 컨슈머 애플리케이션 내부 라이브러리에 "연결이 끊어지면 3초 대기 후 재연결을 시도하라"는 지수 백오프 설정이 들어있다고 가정해 보겠습니다. 그런데 브로커의 redistribution-delay가 2000(2초)으로 설정되어 있다면 어떻게 될까요? 컨슈머는 규정대로 3초를 기다렸다가 정상적으로 원래 브로커에 다시 접속했지만, 브로커는 이미 2초 만에 참을성을 잃고 메시지를 다른 곳으로 모두 던져버린 후입니다.
  • 고려 사항: 브로커의 재분배 대기 시간은 "컨슈머가 연결 실패를 인지하고, 백오프 타이머를 거쳐, 다시 TCP 세션을 맺는 데 걸리는 최대 시간"보다 반드시 넉넉하게 길어야 합니다. 클라이언트가 3초 간격으로 재연결을 시도한다면, 브로커의 대기 시간은 최소 5초 이상으로 설정하여 클라이언트에게 돌아올 수 있는 충분한 '유예 기간'을 주어야 합니다.

3. 자바 가상 머신(JVM)의 Stop-The-World (GC 멈춤)

종종 네트워크 망 자체는 아무런 문제가 없는데 브로커가 컨슈머의 연결을 끊어버리는 경우가 있습니다. 이는 대부분 컨슈머 애플리케이션의 가비지 컬렉션(GC) 때문에 발생합니다.

  • 침묵의 원인: 컨슈머 측 애플리케이션의 메모리가 꽉 차서 무거운 Full GC가 발생하면, 자바 가상 머신은 스레드를 모두 멈추는 'Stop-The-World' 상태에 빠집니다. 애플리케이션 스레드가 멈추었으므로 브로커로 주기적인 하트비트(Heartbeat/KeepAlive) 핑을 보내지 못하게 됩니다. 브로커는 응답이 없는 컨슈머의 세션을 타임아웃 처리하고 연결을 날려버립니다.
  • 고려 사항: 수 초 후 GC가 끝나면 컨슈머는 다시 멀쩡하게 활동을 재개합니다. 인프라 운영자는 APM(Application Performance Monitoring) 도구를 통해 컨슈머 애플리케이션들의 평균적이고 최대인 GC 멈춤 시간을 파악해야 합니다. 이 멈춤 시간 동안 브로커가 메시지를 빼돌리지 않도록, redistribution-delay는 최대 GC 소요 시간보다 길게 설정되어야 스레드 일시 정지로 인한 대규모 메시지 이동을 방어할 수 있습니다.

4. 클라우드 환경의 롤링 배포(Rolling Update)와 파드(Pod) 재시작

쿠버네티스(Kubernetes)나 AWS Auto Scaling 그룹 기반의 클라우드 네이티브 환경에서는 애플리케이션의 배포와 재시작 패턴이 과거의 베어메탈 서버 시대와 완전히 다릅니다.

  • 배포 시나리오: 새로운 버전의 컨슈머 애플리케이션을 배포할 때, 쿠버네티스는 기존 파드를 종료(Terminating)하고 새로운 파드를 띄웁니다. 이때 컨슈머가 일시적으로 0대가 되거나 교체되는 공백기가 수 초에서 수십 초간 발생합니다.
  • 고려 사항: 만약 대기 시간이 너무 짧다면, 롤링 배포를 할 때마다 브로커 클러스터 내부에서는 엄청난 양의 메시지 대이동(I/O 폭풍)이 발생하게 됩니다. 컨테이너 이미지가 다운로드되고 애플리케이션의 스프링 부트(Spring Boot) 컨텍스트가 올라가서 브로커에 붙기까지 걸리는 부팅 시간을 계산해야 합니다. 배포 시 발생하는 이 일시적인 '컨슈머 부재' 상태를 인프라가 묵묵히 기다려 주도록 대기 시간을 세팅하는 것이 네트워크 오버헤드를 아끼는 핵심입니다.

아키텍처 결론 및 최적 수치 산정 가이드

redistribution-delay는 단순히 '기다리는 시간'이 아닙니다. 이는 분산 시스템에서 필연적으로 발생하는 네트워크의 불안정성과 애플리케이션의 지연 현상을 인프라가 얼마나 포용해 줄 것인가를 결정하는 '관용도(Tolerance) 스위치'입니다.

가장 이상적인 수치를 도출하기 위해서는 다음의 기준을 논리적으로 종합하여 산정하시기 바랍니다.

  1. 클라이언트 재연결 소요 시간 확인: 컨슈머 라이브러리에 설정된 최대 백오프 지연 시간을 확인합니다.
  2. 애플리케이션 지연 시간 확인: APM을 통해 확인된 가장 긴 애플리케이션 GC 멈춤 시간이나, 컨테이너 재시작 부팅 시간을 확인합니다.
  3. 버퍼 타임 추가: 위에서 확인된 시간 중 가장 긴 시간에, 여유 버퍼로 대략 이삼 초 가량을 더해줍니다.

결과적으로, 일반적인 엔터프라이즈 내부망 환경에서는 이 수치를 극단적인 0이나 너무 긴 수 분 단위가 아닌, 대략 5000에서 10000(5초 ~ 10초) 사이로 조율하는 것이 가장 안정적인 부하 분산과 시스템 방어를 이끌어내는 모범 사례(Best Practice)입니다. 인프라의 상황을 수치로 정확히 치환하여, 어떠한 네트워크 출렁임에도 핑퐁 장애가 발생하지 않는 견고한 브로커 클러스터를 완성하시기 바랍니다.

반응형