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

'db.redo.log' 파일의 역할과 갑작스러운 전원 차단 시 복구 시나리오는?

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

'db.redo.log' 파일의 역할과 갑작스러운 전원 차단 시 복구 시나리오는?

ActiveMQ KahaDB 스토리지 엔진의 내부 디렉토리를 살펴보면, 메시지 원본이 저장되는 db-*.log 파일과 B-Tree 인덱스가 저장되는 db.data 파일 외에 유독 눈에 띄는 파일이 하나 더 있습니다. 바로 db.redo.log 파일입니다.

데이터베이스 시스템에서 '리두 로그(Redo Log)' 또는 'WAL(Write-Ahead Log)'이라고 불리는 이 컴포넌트는, 예기치 않은 서버 전원 차단이나 커널 패닉 등 치명적인 재난 상황에서 데이터를 완벽하게 복원하기 위한 최후의 보루입니다.

이 가이드에서는 KahaDB가 왜 메시지 저널(db-*.log) 외에 별도의 리두 로그를 운영하는지 그 본질적인 이유를 파헤치고, 전원이 강제로 차단된 후 브로커가 재시작될 때 시스템 내부에서 벌어지는 치열한 데이터 복구 시나리오를 상세히 해부합니다.


1. B-Tree 인덱스(db.data)의 치명적인 약점

앞선 포스팅에서 KahaDB의 인덱스 파일인 db.data가 고속 탐색을 위해 B-Tree 자료구조를 사용한다고 설명했습니다. B-Tree는 탐색에는 극도로 유리하지만, 데이터를 삽입하거나 삭제할 때 치명적인 물리적 취약점을 가집니다.

  • 노드 분할(Split)과 병합(Merge)의 위험성: 새로운 메시지가 들어와 인덱스 트리 특정 노드의 용량이 꽉 차면, 트리는 해당 노드를 두 개로 쪼개고 부모 노드의 포인터를 갱신하는 복잡한 재배치 작업을 수행합니다.
  • 불완전한 쓰기(Torn Page): 이 재배치 작업은 브로커의 힙 메모리에서 먼저 이루어진 뒤, 체크포인트(Checkpoint) 주기가 도래하면 물리적 디스크의 db.data 파일에 덮어써집니다(Overwrite). 만약 디스크에 덮어쓰기를 절반쯤 진행했는데 서버의 전원이 갑자기 나가버린다면 어떻게 될까요?
  • 결과: db.data 파일의 절반은 과거의 트리 구조, 나머지 절반은 새로운 트리 구조가 섞인 끔찍한 코럽션(Corruption, 파일 손상) 상태가 됩니다. 브로커가 재부팅되어 이 깨진 인덱스를 읽는 순간 시스템은 완전히 마비됩니다.

2. 'db.redo.log'의 정체: 인덱스를 위한 보호막

이러한 인덱스 파일 손상을 원천적으로 차단하기 위해 고안된 장치가 바로 db.redo.log입니다. 핵심 원칙은 "원본 인덱스 파일(db.data)을 수정하기 전에, 내가 지금부터 인덱스의 어느 부분을 어떻게 수정할 것인지 '계획'을 먼저 안전한 곳에 적어둔다"는 것입니다.

  • 동작 원리 (Write-Ahead Logging): 브로커가 체크포인트를 수행하여 메모리의 변경된 B-Tree 노드(Dirty Page)들을 db.data에 쓰기 직전, KahaDB는 먼저 그 변경 내역을 db.redo.log 파일의 맨 끝에 순차적으로(Append-only) 빠르게 기록합니다.
  • 역할 분담:
    • db-*.log 파일: 클라이언트가 보낸 '메시지 본문(Payload)'을 안전하게 저장합니다.
    • db.redo.log 파일: 브로커 내부에서 관리하는 '인덱스(B-Tree)의 변경 이력'만을 안전하게 저장합니다.
  • db.redo.log에 기록이 무사히 완료되어야만, 비로소 브로커는 실제 db.data 파일의 구조를 변경하기 시작합니다.

3. 갑작스러운 전원 차단(Power Outage) 시의 단계별 복구 시나리오

운영 중 서버 랙의 전원 케이블이 뽑히는 재난이 발생했다고 가정해 보겠습니다. 서버 전원이 다시 복구되고 ActiveMQ 브로커 프로세스가 기동되는 순간, KahaDB는 다음과 같은 단계로 스스로를 치유합니다.

Phase 1: 클린 셧다운(Clean Shutdown) 검사
브로커가 시작되면 가장 먼저 db.data 파일의 헤더를 읽어, 지난번 종료가 정상적인 프로세스 종료였는지 검사합니다. 전원이 강제로 차단되었으므로 헤더에는 "정상 종료되지 않음" 플래그가 남아있습니다. KahaDB는 즉시 인덱스 파일이 오염되었을 가능성이 있다고 판단하고 복구 모드에 돌입합니다.

Phase 2: 리두 로그(Redo Log) 재생 (Replay)
브로커는 무작정 무거운 저널 파일(db-*.log) 전체 스캔을 시작하지 않습니다. 가장 먼저 작고 가벼운 db.redo.log 파일을 엽니다.

  • 브로커는 전원이 차단되기 직전에 기록되었던 "인덱스 변경 계획"들을 시간순으로 쭉 읽어 들입니다.
  • 그리고 이 계획들을 바탕으로, 깨져버린 db.data 파일의 B-Tree 노드 블록들을 메모리 위에서 하나하나 퍼즐 맞추듯 원래의 올바른 상태로 다시 조립(Replay)합니다.
  • 이 작업은 인덱스의 변경 이력만 쫓아가므로 디스크 I/O가 매우 적어 수 초 이내에 초고속으로 완료됩니다.

Phase 3: 트랜잭션 롤백 및 최종 동기화
퍼즐이 맞춰지면, 브로커는 완료되지 못한(Commit 되지 않은) 찌끄러기 트랜잭션들을 버리고(Rollback), 완벽하게 복구된 B-Tree 인덱스를 다시 db.data 파일에 깨끗하게 플러시(Flush)합니다. 이후 클라이언트의 연결을 정상적으로 수락하며 서비스가 재개됩니다.


4. 아키텍처적 트레이드오프와 성능 튜닝

db.redo.log 덕분에 브로커는 전원이 날아가도 수 시간짜리 '전체 파일 스캔(Full Rebuild)'의 악몽을 피하고 수 초 만에 인덱스를 복구할 수 있습니다. 하지만 시스템 공학에 공짜는 없습니다.

  • Double Write 페널티: 인덱스 데이터를 쓸 때 db.redo.log에 한 번, db.data에 한 번, 총 두 번의 디스크 쓰기가 발생합니다. 디스크 I/O 대역폭이 극도로 부족한 환경에서는 이 두 번의 쓰기 작업이 체크포인트 지연을 유발할 수 있습니다.
  • 튜닝 포인트 (enableIndexWriteAsync):
    극단적인 실시간 처리 성능이 복구 속도보다 더 중요한 비즈니스 환경이라면, KahaDB 설정에서 enableIndexWriteAsync="true" 속성을 고려할 수 있습니다. 이 옵션은 인덱스 쓰기를 비동기로 전환하여 I/O 블로킹을 해소하지만, 전원 차단 시 db.redo.log가 완벽히 기록되지 않아 결국 전체 저널 파일을 스캔해야 하는 리스크를 감수해야 합니다.

결론적으로 db.redo.log는 평상시에는 묵묵히 디스크 한켠을 차지하고 있지만, 시스템이 가장 끔찍한 재난을 맞이했을 때 브로커의 기동 시간을 수십 분에서 수 초로 단축해 주는 마법 같은 안전장치입니다. 인프라 설계 시 이 작은 로그 파일의 위력을 이해하고, 안정적인 디스크 I/O 환경을 보장해 주어야 완벽한 무장애 시스템을 완성할 수 있습니다.

반응형