KahaDB의 'ignoreMissingJournalfiles' 옵션 사용 시 주의점은?
ActiveMQ KahaDB 스토리지 엔진을 운영하는 인프라 엔지니어가 가장 식은땀을 흘리는 순간은, 서버 점검이나 예기치 않은 전원 차단 이후 브로커를 재시작했을 때 java.io.IOException: Could not locate data file db-*.log라는 끔찍한 에러 로그와 함께 브로커 프로세스가 그대로 죽어버리는 상황입니다.
이 에러는 브로커의 B-Tree 인덱스(db.data)가 가리키고 있는 특정 물리적 저널 파일(db-*.log)이 디스크 상에 존재하지 않을 때 발생합니다. 시스템은 데이터의 무결성이 깨졌다고 판단하여 추가적인 2차 피해를 막기 위해 기동 자체를 거부하는 방어 기제를 작동시킨 것입니다.
이때 멈춰버린 서비스(브로커)를 강제로라도 띄우기 위해 구글링을 거쳐 마주하게 되는 마법의 설정 옵션이 바로 KahaDB의 ignoreMissingJournalfiles="true"입니다.
이 옵션을 켜면 브로커는 기적처럼 에러를 무시하고 정상적으로 기동됩니다. 하지만 이 옵션은 시스템의 근본적인 원인을 치료하는 백신이 아니라, 당장의 고통을 잊게 만드는 치명적인 마약과 같습니다. 본 가이드에서는 이 옵션을 사용할 때 아키텍처 내부에서 벌어지는 일과, 엔지니어가 반드시 감당해야 할 치명적인 주의점들을 상세히 해부합니다.

1. 저널 파일(Journal File) 누락의 근본 원인
브로커가 멀쩡히 구동되다가 갑자기 파일이 사라지는 마술은 존재하지 않습니다. 파일 누락은 대부분 다음과 같은 물리적 또는 관리적 재난의 결과입니다.
- 물리적 디스크 손상: 스토리지(SAN, NAS)의 일시적인 마운트 해제, 혹은 하드 디스크의 배드 섹터(Bad Sector)로 인해 파일 시스템 레벨에서 파일이 증발하거나 읽을 수 없게 된 경우입니다.
- 인적 오류 (Human Error): 디스크 용량이 꽉 차는 장애(Disk Full)가 발생했을 때, 다급해진 관리자가 터미널에서 오래되어 보이는
db-1.log,db-2.log파일들을 백업 없이rm -rf명령어로 수동 삭제해 버린 경우입니다. - OS 페이지 캐시 증발: 디스크 동기화 옵션(
journal-sync-transactional="false")을 끈 상태에서 서버 전원이 차단되었을 때, OS 메모리에만 있던 파일 정보가 디스크에 써지기 전에 날아간 경우입니다.
2. 'ignoreMissingJournalfiles' 옵션의 파괴적인 동작 원리
KahaDB 설정에 <kahaDB directory="..." ignoreMissingJournalfiles="true"/>를 부여하고 브로커를 시작하면 내부적으로 무서운 일이 벌어집니다.
브로커는 인덱스(db.data)를 읽어 들이며 디스크의 파일들과 대조(Reconciliation) 작업을 수행합니다. 이때 누락된 저널 파일을 발견하면, 브로커는 기동을 멈추는 대신 해당 파일과 연관된 B-Tree 인덱스의 모든 포인터 레코드를 강제로 잘라내고(Drop) 삭제해 버립니다.
즉, "이 파일이 없으니, 애초에 이 파일 안에 있던 데이터는 세상에 존재하지 않았던 것으로 간주하겠다"는 극단적인 타협을 통해 브로커의 상태를 억지로 '정상(Valid)'으로 둔갑시키는 것입니다.
3. 도입 시 반드시 감수해야 할 3가지 치명적 리스크
이 옵션을 켤 때 엔지니어는 다음의 세 가지 재난을 시스템이 묵인하도록 허락하는 것과 같습니다.
A. 확정적인 데이터 유실 (Silent Data Loss)
사라진 저널 파일 내부에 아직 컨슈머가 처리하지 않은 대기 중인 메시지(Pending Message)가 있었다면, 그 메시지들은 복구할 기회조차 없이 영구적으로 증발합니다. 브로커는 더 이상 이 파일이 없다고 불평하지 않으므로, 관리자는 정확히 어떤 비즈니스 데이터(결제, 주문 등)가 몇 건이나 날아갔는지 추적할 방법조차 잃게 됩니다.
B. 극심한 메시지 중복 수신 (Duplicate Delivery / Zombie Messages)
가장 골치 아픈 부작용입니다. KahaDB는 메시지의 인입(ADD)과 처리 완료(ACK)를 시간순으로 저널 파일에 기록합니다.
만약 누락된 저널 파일에 메시지의 본문이 아니라 '처리 완료(ACK) 기록'이 들어있었다면 어떻게 될까요?
브로커는 누락된 파일을 무시하면서 ACK 기록들을 함께 삭제해 버립니다. 브로커의 관점에서는 과거의 다른 파일에 남아있던 원본 메시지들이 "아직 처리되지 않은 상태"로 부활하게 됩니다. 결과적으로 이미 며칠 전에 정상적으로 소비했던 수천 개의 메시지가 큐에 다시 나타나(Redelivery) 컨슈머들에게 쏟아지며, 시스템 전반의 멱등성(Idempotency)을 산산조각 냅니다.
C. 인프라 결함의 영구적 은폐 (Masking Hardware Failure)
이 옵션을 임시로 켜는 것을 넘어, 설정 파일에 영구적으로 true로 남겨두는 것은 최악의 안티 패턴(Anti-Pattern)입니다.
만약 디스크 컨트롤러에 물리적인 결함이 생겨 간헐적으로 파일 저장에 실패하는 하드웨어 장애가 발생하더라도, 브로커는 에러를 뿜지 않고 조용히 데이터를 버리면서 계속 구동됩니다. 모니터링 시스템은 브로커 프로세스가 살아있으므로 정상(Green) 상태를 표출하고, 비즈니스 부서에서 데이터 누락 클레임이 폭주한 뒤에야 사태를 파악하게 됩니다.
4. 무결성을 지키는 올바른 장애 복구 시나리오 (DR Guide)
그럼에도 불구하고 서비스 다운타임을 끝낼 유일한 방법이 이 옵션뿐이라면, 외과 수술처럼 정교하게 치고 빠지는 전략이 필요합니다.
- 1단계 (골든타임 보존): 브로커를 즉시 내리고, 현재 KahaDB 폴더 전체를 다른 디스크나 경로에 압축하여
tar로 백업합니다. 나중에 유실된 데이터를 수동으로라도 대조하려면 원본 상태 보존이 필수입니다. - 2단계 (수술 진행):
broker.xml(또는activemq.xml)에서ignoreMissingJournalfiles="true"를 켭니다. - 3단계 (인덱스 정리): 브로커를 기동시킵니다. 브로커가 켜지면서 누락된 파일의 인덱스를 정리하고 로딩을 완료하는 것을 로그로 확인합니다.
- 4단계 (수술 종료 및 봉합 - 가장 중요): 브로커가 완전히 켜져서 큐 상태가 갱신된 것을 확인했다면, 즉시 브로커 프로세스를 다시 종료(Shutdown) 합니다.
- 5단계 (정상화): 설정 파일로 돌아가
ignoreMissingJournalfiles="false"로 롤백하거나 아예 해당 줄을 삭제합니다. 그리고 브로커를 다시 기동하여 클라이언트의 접속을 허용합니다.
요약하자면 ignoreMissingJournalfiles는 엉켜버린 매듭을 풀지 못할 때 매듭 자체를 칼로 잘라버리는 극약 처방입니다. 서비스 복구를 위해 어쩔 수 없이 뽑아든 칼이라 할지라도, 그로 인해 잘려 나간 데이터의 무결성(유실과 중복)을 애플리케이션 레벨에서 어떻게 수습할지 반드시 대책을 마련한 뒤에 실행에 옮겨야 합니다.
'1. 개발 > 1.8. ActiveMQ' 카테고리의 다른 글
| 'Disk Scan' 주기가 짧을 때 발생하는 I/O Wait 현상은? (0) | 2026.04.02 |
|---|---|
| Artemis의 'Mapped Memory' 페이징 전략이 성능을 높이는 이유는? (0) | 2026.04.01 |
| 'tempUsage'가 꽉 찼을 때 Non-persistent 메시지의 운명은? (0) | 2026.04.01 |
| 'Producer Flow Control' 발생 시 로그에 찍히는 특정 메시지 패턴은? (0) | 2026.04.01 |
| 'Async Send' 사용 시 브로커의 승인(Ack) 없이 보낼 수 있는 최대 양은? (0) | 2026.04.01 |