Journal 파일의 'Compaction' 주기가 늦어질 때 발생하는 디스크 부하?
엔터프라이즈 메시지 브로커(ActiveMQ Artemis 등)의 스토리지 엔진은 극강의 처리 속도를 달성하기 위해 데이터를 절대 덮어쓰지 않고 파일의 맨 끝에 계속 이어 붙이기만 하는 'Append-only(추가 전용)' 방식을 채택하고 있습니다.
하지만 이 방식에는 치명적인 부작용이 따릅니다. 컨슈머(Consumer)가 이미 소비를 완료하여 더 이상 필요 없어진 과거의 메시지(쓰레기 데이터)들이 디스크의 저널 파일 내부에 흉터처럼 그대로 남게 된다는 점입니다. 브로커는 이러한 디스크 낭비를 해결하기 위해, 여러 저널 파일에 듬성듬성 흩어져 있는 '아직 소비되지 않은 유효한 메시지'들만 싹 긁어모아 새로운 저널 파일 하나로 압축해 옮겨 적고, 쓰레기 데이터만 남은 기존 파일들을 일괄 삭제합니다. 이 백그라운드 정리 작업이 바로 '컴팩션(Compaction)'입니다.
만약 설정 오류나 비정상적인 트래픽 패턴으로 인해 이 컴팩션 주기가 늦어지거나 제때 동작하지 않는다면, 시스템 인프라에는 어떤 치명적인 연쇄 장애가 발생할까요? 이 가이드에서는 컴팩션 지연이 불러오는 디스크 부하와 아키텍처의 붕괴 과정을 상세히 분석합니다.

1. 극심한 데이터 파편화(Fragmentation)와 용량 고갈
컴팩션이 지연될 때 가장 먼저 나타나는 직관적인 증상은 디스크 파티션의 용량 고갈(Disk Full)입니다.
- 파편화의 늪: 파일 하나에 10만 개의 메시지가 들어있다고 가정해 보겠습니다. 컨슈머가 이 중 9만 9천 9백 개를 정상적으로 처리했습니다. 하지만 단 100개의 메시지가 처리되지 못한 채(예: 컨슈머 로직 오류, 혹은 의도적인 지연 메시지) 남아있다면, 브로커는 이 거대한 파일을 통째로 삭제할 수 없습니다.
- 무의미한 디스크 점유: 컴팩션이 작동하여 이 100개의 메시지를 다른 곳으로 이사(Migration)시켜 주어야만 원본 파일을 삭제하고 디스크 공간을 회수할 수 있습니다. 컴팩션이 지연되면 이처럼 '거의 다 비어있지만 삭제할 수는 없는' 껍데기 파일들이 수백, 수천 개씩 누적되며 순식간에 수백 기가바이트의 디스크를 삼켜버립니다. 결과적으로 브로커는 스토리지 한계치에 도달하여 모든 프로듀서(Producer)의 접속을 차단하게 됩니다.
2. 컴팩션 폭풍(Compaction Storm)에 따른 디스크 I/O 스파이크
컴팩션이 아예 안 도는 것도 문제지만, 너무 오랫동안 참았다가 한꺼번에 도는 것이 사실상 가장 무서운 성능 병목의 원인입니다.
- 지연된 숙제의 대가: 브로커 설정에서 컴팩션을 유발하는 임계치가 너무 높게 잡혀 있다면, 디스크에 이미 수천 개의 파편화된 저널 파일이 쌓인 뒤에야 비로소 컴팩션 스레드가 깨어납니다.
- I/O 경합(Contention) 발생: 깨어난 컴팩션 스레드는 밀린 숙제를 하기 위해 수천 개의 파일을 동시에 열어서 유효한 메시지를 찾기 위한 미친 듯한 디스크 읽기(Read) 작업을 시작합니다. 동시에 새로운 압축 파일에 메시지를 몰아넣는 대규모 쓰기(Write) 작업을 수행합니다.
- 메인 스레드 기아 상태(Starvation): 이 엄청난 백그라운드 디스크 I/O 폭주는 운영체제의 디스크 대역폭을 완전히 독점해 버립니다. 정작 가장 중요한 '클라이언트가 실시간으로 보내는 새로운 메시지'를 저널에 기록해야 하는 메인 라우팅 스레드들이 디스크를 사용하지 못해 대기 상태(I/O Wait)에 빠지게 됩니다. 클라이언트 입장에서는 평소 1밀리초면 끝나던 전송이 갑자기 수 초 이상 걸리는 원인 불명의 타임아웃 장애를 겪게 됩니다.
3. 브로커 재시작(Restart) 시의 치명적인 지연 시간
운영 중 발생한 디스크 부하를 해결하기 위해(또는 정기 패치를 위해) 브로커를 재시작하게 된다면, 컴팩션 지연이 남긴 또 다른 폭탄이 터집니다.
- 무거운 리플레이(Replay): 브로커가 기동될 때, 메모리의 메시지 라우팅 트리를 복원하기 위해 디스크에 남은 모든 저널 파일을 처음부터 끝까지 순차적으로 스캔해야 합니다.
- 버려진 시간: 컴팩션이 잘 되어 파일이 10개로 압축되어 있었다면 수 초 안에 끝날 복구 작업이, 컴팩션이 안 되어 쓰레기 데이터가 가득 섞인 1,000개의 파일을 스캔하느라 수십 분이 소요됩니다. 재시작 지연은 곧 서비스의 다운타임(Downtime) 증가로 직결됩니다.
4. 아키텍처 설계 시의 모범 튜닝 가이드 (Best Practices)
이러한 디스크 부하와 I/O 스파이크를 막으려면, 컴팩션이 '거대한 폭풍'이 되기 전에 '작고 잦은 산들바람'처럼 꾸준히 백그라운드에서 동작하도록 설정 파일을 튜닝해야 합니다. Artemis의 broker.xml에서 다음 두 가지 핵심 옵션을 반드시 점검하십시오.
- compact-min-files (최소 파일 개수 기준):
컴팩션을 시작하기 위해 디스크에 쌓여야 하는 최소 저널 파일의 개수입니다. 기본값은 보통 10입니다. 이 값을 너무 크게(예: 100) 설정하면 한꺼번에 100개의 파일을 압축해야 하므로 I/O 스파이크가 발생합니다. 트래픽이 많다면 차라리 10에서 20 사이의 낮은 값을 유지하여, 적은 수의 파일이 쌓일 때마다 즉각적으로 작은 규모의 컴팩션이 자주 일어나도록 유도하는 것이 디스크 대역폭을 일정하게 유지하는 비결입니다. - compact-percentage (압축률 기준):
저널 파일 내의 쓰레기 데이터(소비 완료된 메시지) 비율이 몇 퍼센트에 도달했을 때 컴팩션 대상으로 삼을 것인지를 결정합니다. 기본값은 보통 30퍼센트입니다. 이 값을 극단적으로 낮추면 멀쩡한 파일들을 계속 들쑤시며 불필요한 디스크 읽기/쓰기를 유발하므로, 기본값을 유지하거나 인프라의 여유 공간에 맞춰 보수적으로 접근해야 합니다.
결론적으로 저널 컴팩션은 방치하면 인프라를 무너뜨리는 시한폭탄이 되지만, 주기를 세밀하게 조율하면 디스크 I/O를 최적의 상태로 유지해 주는 브로커의 훌륭한 청소부입니다. 시스템의 트래픽 패턴(메시지가 즉시 소비되는지, 오래 큐에 대기하는지)을 모니터링하여 인프라에 가장 적합한 컴팩션 타이밍을 설계하시기 바랍니다.
'1. 개발 > 1.8. ActiveMQ' 카테고리의 다른 글
| 'fsync'와 'datasync' 명령이 디스크 컨트롤러에 전달되는 방식은? (0) | 2026.03.23 |
|---|---|
| Libaio와 NIO의 OS 수준 인터럽트 처리 방식 차이는? (0) | 2026.03.23 |
| Artemis의 Journal 방식이 'Append-only'를 고수하는 이유는? (0) | 2026.03.23 |
| 'journalMaxFileLength' 설정이 체크포인트 주기에 미치는 영향은? (0) | 2026.03.23 |
| KahaDB 인덱스 복구(Cleanup) 시 발생하는 성능 지연 시간은? (0) | 2026.03.22 |