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

'journalMaxFileLength' 설정이 체크포인트 주기에 미치는 영향은?

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

'journalMaxFileLength' 설정이 체크포인트 주기에 미치는 영향은?

ActiveMQ 메시징 시스템을 운영하며 디스크 I/O 병목 현상이나 예상치 못한 스토리지 고갈 문제를 마주했을 때, 가장 먼저 점검해야 할 요소는 KahaDB의 스토리지 설정입니다. 그중에서도 journalMaxFileLength 옵션은 단순히 데이터가 기록되는 로그 파일(db-*.log)의 물리적 크기를 결정하는 데 그치지 않습니다.

이 설정값은 브로커의 메모리에 있는 인덱스를 디스크로 안전하게 동기화하는 '체크포인트(Checkpoint)' 주기와 낡은 데이터를 정리하는 가비지 컬렉션(GC) 타이밍을 지배하는 핵심 통제 장치입니다. 본 가이드에서는 이 설정이 시스템 전체의 성능과 안정성에 미치는 아키텍처적 파급 효과를 상세히 분석합니다.


1. KahaDB의 체크포인트(Checkpoint) 동작 매커니즘

설정값의 영향을 이해하기 위해서는 먼저 브로커 내부의 체크포인트가 무엇인지 명확히 알아야 합니다.

KahaDB는 메시지의 원본 본문을 저널 파일(db-*.log)에 순차적으로 빠르게 밀어 넣고, 이 메시지들의 위치를 가리키는 포인터(인덱스)는 힙 메모리의 B-Tree 구조로 관리하여 탐색 속도를 극대화합니다. 하지만 메모리는 휘발성이므로, 시스템에 장애가 발생했을 때 이 인덱스가 날아가는 것을 방지하기 위해 주기적으로 메모리의 B-Tree 상태를 물리적 디스크의 db.data 파일에 덮어쓰는 작업을 수행합니다. 이것이 바로 체크포인트입니다.

체크포인트는 기본적으로 시간 간격(checkpointInterval, 기본값 5초)에 의해 백그라운드 스레드에서 주기적으로 발생합니다. 하지만 KahaDB의 내부 구현상, 저널 파일이 가득 차서 새로운 파일로 교체되는 '롤오버(Rollover)' 시점에도 강한 영향을 받게 됩니다. 파일 단위로 데이터의 쓰기 상태가 전환될 때 브로커는 데이터의 무결성을 보장하고 가비지 컬렉션을 수행하기 위해 내부 메타데이터를 대대적으로 갱신하기 때문입니다.


2. journalMaxFileLength 설정에 따른 극단적 트레이드오프

journalMaxFileLength의 기본값은 32MB입니다. 트래픽의 규모와 비즈니스 환경에 맞지 않게 이 값을 너무 작거나 크게 변경하면, 체크포인트와 정리 작업의 주기가 어긋나며 치명적인 병목 현상을 유발합니다.

A. 크기를 너무 작게 설정했을 때 (예: 10MB)

메시지 유입량이 많은 시스템에서 파일 크기를 극단적으로 줄이면 '롤오버 폭풍(Rollover Storm)'이 발생합니다.

  • 무의미한 잦은 파일 생성: 초당 수십 메가바이트의 트래픽이 들어온다면, 브로커는 1초에도 몇 번씩 기존 파일을 닫고 새로운 저널 파일을 디스크에 할당해야 합니다.
  • 오버헤드 스파이크: 저널 파일이 교체될 때마다 브로커 내부에서는 가비지 컬렉션 대상 파일을 스캔하고, 파일 핸들을 열고 닫는 I/O 블로킹 작업이 빈번하게 일어납니다. 이는 시간 주기로 돌아가는 정상적인 체크포인트 스레드와 맞물려 디스크 헤더를 끊임없이 혹사시키며, CPU의 I/O Wait 수치를 급등시키는 주범이 됩니다.

B. 크기를 너무 크게 설정했을 때 (예: 1GB 이상)

파일 크기를 대폭 늘리면 잦은 롤오버로 인한 오버헤드는 줄어들고 순차 쓰기 성능은 일시적으로 극대화되는 것처럼 보입니다. 하지만 이 방식은 디스크 공간 회수(Cleanup) 지연이라는 훨씬 더 무서운 폭탄을 안고 있습니다.

  • 가비지 컬렉션의 한계: KahaDB의 가비지 컬렉션은 개별 메시지 단위가 아니라 오직 '저널 파일(db-*.log) 단위'로만 삭제가 가능합니다. 파일 내부에 기록된 수십만 개의 메시지 중 단 1개의 메시지라도 컨슈머가 처리하지 않았거나 데드 레터 큐(DLQ)로 빠지지 않고 남아있다면, 브로커는 그 1GB짜리 거대한 파일을 절대 디스크에서 삭제하지 못합니다.
  • 디스크 고갈 장애: 파일 하나가 채워지는 주기가 너무 길어지면, 대부분의 데이터가 이미 소비되어 쓸모없는 쓰레기 데이터임에도 불구하고 디스크 공간이 즉각적으로 반환되지 않습니다. 결과적으로 브로커 스토리지 한계치(Store Usage Limit)에 빠르게 도달하여 프로듀서의 연결이 전면 차단되는 장애를 겪게 됩니다.

3. 체크포인트와 롤오버의 최적화 동기화 전략

안정적인 ActiveMQ 아키텍처를 구성하려면, 이 파일 롤오버 주기와 정기적인 체크포인트 주기가 톱니바퀴처럼 조화롭게 맞물리도록 설계해야 합니다.

  1. 처리량(TPS)과 메시지 크기 기반의 용량 산정:
    시스템에 인입되는 평균 메시지의 크기와 초당 트래픽을 계산하여, 하나의 저널 파일이 채워지는 데 최소한 1분에서 5분 정도의 시간이 걸리도록 journalMaxFileLength를 튜닝하는 것이 가장 이상적입니다. (예: 초당 1MB의 데이터가 들어온다면, 약 100MB에서 200MB 사이로 설정)
  2. checkpointInterval과의 비율 조정:
    파일 크기를 늘렸다면, 상대적으로 체크포인트 스레드가 db.data에 B-Tree를 기록하는 빈도는 5초 단위의 기본값을 유지하거나 인프라의 I/O 성능에 맞춰 적절히 늘려 디스크의 동시 접근 경합을 줄여주어야 합니다.
  3. 디스크 파티션 분리 (Best Practice):
    성능을 극한으로 끌어올리려면 브로커 서버 내에서 db-*.log 파일이 저장되는 디렉토리와 인덱스가 저장되는 디렉토리를 물리적으로 다른 디스크 볼륨(예: 저널은 고속 NVMe SSD, 인덱스 체크포인트용은 별도 디스크)으로 분리하십시오. 이렇게 하면 로그 순차 쓰기와 체크포인트 랜덤 쓰기가 서로 간섭하지 않아 I/O 지연이 극적으로 해소됩니다.

요약하자면 journalMaxFileLength는 스토리지 단의 파일 크기 설정처럼 보이지만, 실제로는 브로커 메모리의 체크포인트 메커니즘과 가비지 컬렉션 생태계 전반을 통제하는 마스터키입니다. 비즈니스 도메인의 메시지 소비 패턴(빠르게 소모되는지, 장기 체류하는지)을 정확히 분석하여 최적의 균형점을 찾으시길 바랍니다.

반응형