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

디스크 조각화(Fragmentation)가 KahaDB 읽기 성능에 미치는 영향?

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

디스크 조각화(Fragmentation)가 KahaDB 읽기 성능에 미치는 영향?

엔터프라이즈 환경에서 ActiveMQ 브로커를 운영할 때, KahaDB 스토리지 엔진은 극단적인 쓰기 속도를 보장하기 위해 '추가 전용(Append-Only)' 방식으로 저널 파일을 생성합니다. 데이터가 디스크의 끝에 순차적으로 계속 쓰이기 때문에, 많은 인프라 엔지니어들은 KahaDB가 디스크 조각화(Fragmentation)로부터 자유로울 것이라고 착각하곤 합니다.

하지만 시스템이 장기간 운영되며 생성과 삭제를 반복하다 보면, 파일 시스템 레벨과 브로커 내부 자료구조 레벨 모두에서 필연적으로 조각화가 발생합니다. 평소에는 빠른 쓰기 속도에 가려져 보이지 않던 이 조각화의 늪은, 브로커가 디스크에서 데이터를 '읽어야 하는(Read)' 특수한 상황에 직면하는 순간 전체 시스템의 I/O를 마비시키는 치명적인 병목으로 돌변합니다.

이 가이드에서는 디스크 조각화가 KahaDB의 읽기 파이프라인을 어떻게 파괴하는지 그 물리적, 논리적 메커니즘을 해부하고, 이를 방어하기 위한 인프라 최적화 전략을 상세히 분석합니다.


1. KahaDB 저널 파일의 역설: 순차 쓰기와 무작위 읽기

KahaDB는 db-1.log, db-2.log와 같은 고정된 크기(기본 32MB)의 저널 파일을 사용하여 메시지를 순차적으로 기록합니다.

메시지가 빠르게 소비(Consume)되어 삭제 처리(ACK)가 되면, KahaDB의 백그라운드 스레드는 더 이상 유효한 데이터가 없는 저널 파일을 찾아내어 파일 시스템에서 통째로 지워버립니다. 문제는 이 지워진 공간들이 디스크 곳곳에 '이빨 빠진 구멍(Free Space Hole)'처럼 산재하게 된다는 점입니다.

이후 브로커가 새로운 저널 파일을 생성할 때, 운영체제(OS)의 파일 시스템은 물리적으로 연속된 섹터를 할당하지 못하고 디스크 곳곳에 흩어진 빈 공간들을 끌어모아 하나의 논리적인 파일을 만들어냅니다. 파일 탐색기에서는 하나의 온전한 db-100.log 파일로 보이지만, 물리적 하드웨어 레벨에서는 수백 개의 조각으로 찢겨 저장된 '심각하게 조각난 파일'이 탄생하는 것입니다.


2. 읽기(Read) 성능이 붕괴되는 물리적 메커니즘

이렇게 조각난 저널 파일을 읽어야 할 때, 스토리지 컨트롤러에서는 다음과 같은 재난이 발생합니다.

  • Sequential I/O의 Random I/O 강제 변환: 저널 파일은 본래 데이터를 처음부터 끝까지 한 번에 쭉 읽어 들이는 '순차 읽기(Sequential Read)'에 최적화되어 있습니다. 하지만 파일이 물리적으로 조각나 있으면, 디스크 컨트롤러는 논리적으로는 이어져 있는 데이터를 읽기 위해 물리적인 디스크 헤드를 쉴 새 없이 다른 트랙으로 이동(Seek)시켜야 합니다. 순차 I/O가 가장 무거운 연산인 무작위 I/O(Random I/O)로 둔갑하며 디스크 대역폭이 급감합니다.
  • OS 페이지 캐시(Page Cache)의 비효율: 운영체제는 디스크 성능을 높이기 위해 데이터를 읽을 때 주변의 블록까지 한 번에 메모리 캐시로 미리 퍼 올리는 'Read-ahead' 기법을 사용합니다. 파일이 조각나 있으면 물리적으로 인접한 블록에 브로커와 전혀 상관없는 다른 애플리케이션의 데이터나 쓸모없는 찌꺼기 데이터가 섞여 있게 됩니다. 결국 한정된 OS 메모리 캐시에 불필요한 쓰레기 데이터가 적재되며 메모리 낭비와 캐시 적중률(Hit Ratio) 하락을 유발합니다.

3. 브로커 운영 중 직면하는 3가지 치명적 읽기 시나리오

평소 컨슈머가 메시지를 실시간으로 쏙쏙 빼갈 때는(메모리 캐시에서 직접 처리될 때는) 조각화의 악영향을 체감하기 어렵습니다. 진정한 장애는 디스크에서 물리적으로 과거의 데이터를 퍼 올려야 하는 다음 3가지 상황에서 발생합니다.

A. 브로커 서버 재기동 및 인덱스 복구 (Recovery)
브로커 서버를 패치하거나 재시작할 때, 가장 시간이 오래 걸리는 작업은 KahaDB가 기존의 저널 파일들을 처음부터 끝까지 스캔하여 B-Tree 인덱스(db.data)를 메모리에 재건축(Rebuild)하는 과정입니다.
저널 파일들이 심하게 조각나 있다면 수백 MB의 파일을 읽어 들이는 데 평소보다 수십 배의 시간이 소요되며, 브로커는 기약 없는 다운타임(Downtime) 상태에 빠지게 됩니다.

B. Slow Consumer와 과거 데이터 조회
프로듀서는 엄청난 속도로 메시지를 보내는데 컨슈머의 처리 속도가 느려 큐에 수만 건의 메시지가 적체된 상황입니다.
이 메시지들은 이미 힙 메모리에서 밀려나 디스크에만 존재합니다. 뒤늦게 컨슈머가 메시지를 요구하면 브로커는 조각난 저널 파일의 특정 오프셋(Offset)을 찾아 디스크를 긁어야 합니다. 이 과정에서 디스크 I/O Wait가 치솟으며 브로커의 전체 라우팅 스레드가 멈칫거리는 블로킹(Blocking) 현상이 발생합니다.

C. KahaDB 내부 압축(Compaction) 작업의 지연
KahaDB는 공간을 효율적으로 쓰기 위해 유효한 메시지가 얼마 남지 않은 여러 개의 저널 파일을 읽어서 하나의 새로운 파일로 합치는 압축(Compaction) 작업을 백그라운드에서 수행합니다. 소스가 되는 저널 파일들이 조각나 있으면 이 압축 작업 자체가 디스크 I/O를 극심하게 점유하여, 정작 중요한 메인 트래픽(프로듀서의 메시지 저장)을 처리할 디스크 대역폭을 고갈시킵니다.


4. 물리적 조각화를 넘어선 논리적 조각화: db.data (B-Tree)

파일 시스템 레벨의 저널 파일 조각화 외에도, KahaDB 내부의 인덱스 파일인 db.data 파일 자체의 '논리적 조각화' 역시 읽기 성능을 파괴하는 주범입니다.

db.data는 메시지의 저장 위치를 추적하는 B-Tree 자료구조를 담고 있습니다. 큐에 메시지가 끊임없이 들어오고 나가면, B-Tree의 노드(Node)들이 추가되고 분할(Split)되며 삭제됩니다.
시간이 지나면 논리적으로는 인접한 B-Tree의 노드들이 물리적인 db.data 파일 내부에서는 완전히 뒤죽박죽으로 흩어지게 됩니다. 브로커가 특정 메시지를 찾기 위해 B-Tree를 탐색(Traversal)할 때마다 파일의 앞뒤를 미친 듯이 오가며 읽어야 하므로, 인덱스 검색 성능이 바닥으로 곤두박질칩니다.


5. 조각화 방지 및 아키텍처 최적화 전략

이러한 조각화의 늪에서 읽기 성능을 사수하기 위해 인프라 엔지니어는 하드웨어와 소프트웨어 양면의 방어선을 구축해야 합니다.

  1. 저널 파일 사전 할당 (Preallocation) 적용:
    가장 강력한 예방책입니다. activemq.xml에서 KahaDB 옵션에 preallocationStrategy="os_kernel_copy" 또는 zeros를 설정하십시오. 이 옵션을 켜면 브로커가 새로운 저널 파일을 생성할 때 파일 시스템에 32MB의 연속된 물리적 공간을 미리 확보해 달라고 강제합니다. 파일이 점진적으로 커지면서 빈 공간에 흩뿌려지는 것을 원천 차단하여 물리적 조각화를 극적으로 줄입니다.
  2. 정기적인 인덱스(db.data) 재건축 (Rebuild):
    db.data 내부의 논리적 조각화는 운영체제 레벨에서 해결할 수 없습니다. 유지보수 기간에 브로커를 안전하게 내리고, KahaDB 디렉토리 내의 db.datadb.redo 파일을 수동으로 백업 후 삭제하십시오. 이후 브로커를 재기동하면, 파편화되었던 B-Tree 인덱스가 저널 파일을 바탕으로 가장 최적화되고 깔끔한 상태로 메모리에서 새로 조립되어 디스크에 쓰입니다.
  3. 디스크 I/O 분리와 전용 볼륨 사용:
    KahaDB의 저널 디렉토리를 OS 시스템 로그나 다른 애플리케이션과 공유하면 디스크 조각화는 기하급수적으로 악화됩니다. 브로커의 directory 설정은 반드시 포맷이 완료된 깨끗한 전용 디스크 볼륨(XFS 계열 파일시스템 권장)을 독립적으로 마운트하여 사용해야 합니다.
  4. SSD 도입 및 TRIM 활성화:
    물리적인 헤드 이동이 없는 SSD(NVMe)를 사용하면 Random I/O 변환으로 인한 치명적인 지연 시간은 상당 부분 상쇄됩니다. 하지만 SSD 환경이라 하더라도 OS 레벨의 페이지 캐시 비효율성은 그대로 남으므로, 정기적인 fstrim 명령어 수행을 통해 파일 시스템의 여유 공간을 블록 레벨에서 정리해 주는 운영 사이클이 필요합니다.

결론적으로 디스크 조각화는 KahaDB의 무자비한 순차 쓰기 특성과 OS 파일 시스템이 빚어내는 피할 수 없는 부작용입니다. 쓰기 성능에 안심하지 말고, 장애 상황이나 과거 데이터 조회 시 발생할 무거운 '읽기(Read)' 부하를 견뎌낼 수 있도록 저널 파일 사전 할당과 정기적인 인덱스 정비를 아키텍처 운영 지침에 반드시 포함하시기 바랍니다.

반응형