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

브로커 내부의 'In-memory State'와 저장소 데이터 불일치 시 검증법은?

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

브로커 내부의 'In-memory State'와 저장소 데이터 불일치 시 검증법은?

메시지 브로커(ActiveMQ, Artemis 등)는 극단적인 처리 속도와 데이터의 영속성이라는 두 마리 토끼를 잡기 위해, 시스템을 두 개의 세계로 나누어 운영합니다. 하나는 초고속 라우팅과 디스패치를 담당하는 휘발성의 'In-memory State(메모리 상태)'이고, 다른 하나는 서버가 죽어도 데이터를 보존하는 비휘발성의 'Persistent Storage(물리 저장소)'입니다.

정상적인 상황에서 이 두 세계는 체크포인트(Checkpoint)와 저널링(Journaling) 메커니즘을 통해 거울처럼 완벽하게 동기화됩니다. 하지만 예기치 않은 하드웨어 장애나 설정 오류가 개입하는 순간, 이 거울은 깨어지고 메모리가 알고 있는 진실과 디스크가 품고 있는 진실이 어긋나는 '데이터 불일치(Inconsistency)'라는 최악의 아키텍처 재난이 발생합니다.

본 가이드에서는 이 치명적인 불일치 현상이 발생하는 근본 원인을 해부하고, 인프라 엔지니어가 이를 정확하게 진단하고 검증하여 복구하는 트러블슈팅 전략을 상세히 분석합니다.


1. In-memory와 Storage 불일치가 발생하는 3대 원인

브로커 내부에서 데이터의 정합성이 깨지는 이유는 대부분 정상적인 종료 절차(Clean Shutdown)를 밟지 못했을 때 발생합니다.

A. OOM(Out of Memory)으로 인한 JVM의 급사(Sudden Death)
트래픽 폭주로 인해 브로커의 힙 메모리가 한계치를 초과하면, 운영체제의 OOM Killer가 개입하거나 JVM 자체가 패닉에 빠져 즉각 종료됩니다. 이때 메모리의 B-Tree 인덱스 변경 사항이나 큐의 카운터(Depth) 정보가 디스크의 db.data나 저널에 미처 기록(Flush)되지 못하고 허공으로 증발하면서 물리적 저장소와 상태가 완전히 어긋나게 됩니다.

B. 비동기 커밋(Async Commit) 설정의 부작용
성능을 극한으로 끌어올리기 위해 저널의 물리적 쓰기를 비동기로 지연시키는 설정(journal-sync-transactional="false")을 사용 중일 때 서버 전원이 차단되면, 메모리(In-memory State) 상에서는 이미 클라이언트에게 "처리 완료"를 응답했음에도 디스크에는 데이터가 존재하지 않는 유령 트랜잭션이 발생합니다.

C. 외부적인 스토리지 변조 (Human Error)
관리자가 브로커 프로세스가 구동 중이거나 멈춰있는 틈을 타서, 데이터베이스의 ACTIVEMQ_MSGS 테이블에서 임의로 레코드를 DELETE 하거나 파일 시스템의 db-*.log 파일을 수동으로 삭제한 경우입니다. 브로커의 메모리 구조체는 이 외부적인 삭제 사실을 알지 못하므로, 존재하지 않는 파일을 계속해서 참조하려다 치명적인 NullPointerException을 발생시키며 라우팅이 마비됩니다.


2. 데이터 불일치의 3가지 치명적 전조 증상

시스템에 불일치가 발생하면, 모니터링 대시보드와 클라이언트 애플리케이션에서 다음과 같은 기이한 현상들이 동시다발적으로 목격됩니다.

  • 유령 메시지 (Phantom Messages): 관리자 웹 콘솔(또는 JMX)을 확인해 보면 분명히 큐에 500개의 메시지가 대기 중(Queue Depth = 500)이라고 나옵니다. 하지만 수십 개의 컨슈머가 연결되어 있음에도 불구하고 단 1건의 메시지도 소비(Consume)되지 않습니다. 메모리의 카운터만 올라가 있고, 디스크에는 실제 메시지 본문이 없기 때문입니다.
  • 마이너스 큐 카운터 (Negative Queue Depth): 큐의 대기 메시지 수가 -1, -5와 같이 음수로 떨어집니다. 이는 디스크에서 복원된 메시지의 수보다 메모리 상에서 ACK(처리 완료)를 받아 차감된 카운터가 더 많아져 발생하는, 인메모리 구조체의 완벽한 붕괴를 의미합니다.
  • 무한 디페이징 루프 (Infinite Depaging Loop): 페이징(Paging) 모드에서 디스크의 데이터를 메모리로 읽어오려 하지만, 인덱스 정보가 꼬여 있어 브로커가 엉뚱한 파일 주소를 계속 탐색하며 CPU 사용률이 100%로 치솟고 멈춰버립니다.

3. 상태 불일치 진단 및 교차 검증(Verification) 기법

이러한 증상이 나타났을 때, 엔지니어는 감에 의존하지 않고 명확한 지표를 통해 메모리와 디스크 간의 간극을 증명해 내야 합니다.

1단계: JMX 메모리 카운터 vs 물리적 스토리지 크기 대조

가장 먼저 브로커의 인메모리 지표와 실제 물리적 지표의 비율을 의심해야 합니다.

  • JMX 확인: org.apache.activemq:type=Broker,destinationType=Queue,destinationName=YOUR_QUEUE MBean에 접속하여 QueueSize 속성을 확인합니다.
  • 물리적 확인 (KahaDB): 해당 큐의 사이즈가 수백만 건이라고 나오는데, 실제 OS에서 KahaDB 디렉토리(db-*.log)의 총용량을 조회(du -sh)했을 때 불과 수십 메가바이트밖에 되지 않는다면 명백한 데이터 증발 및 카운터 불일치입니다.
  • 물리적 확인 (JDBC): DB를 스토어기로 사용 중이라면, JMX의 QueueSize와 실제 DB에서 SELECT COUNT(*) FROM ACTIVEMQ_MSGS WHERE CONTAINER = 'YOUR_QUEUE' 쿼리의 결과를 직접 비교하여 일치 여부를 검증해야 합니다.

2단계: 브로커 로그의 코럽션(Corruption) 에러 탐지

브로커의 activemq.log 또는 artemis.log를 열고 다음의 핵심 키워드들을 grep 명령어로 추출해냅니다.

  • Corrupt journal record
  • Page count is negative
  • Failed to load message
  • NullPointerException (디스패치 스레드 근처)
    이러한 로그들이 발견된다면, 메모리가 디스크의 특정 블록을 찾지 못해 라우팅 엔진이 헛돌고 있다는 명백한 증거입니다.

3단계: KahaDB / Artemis CLI 데이터 무결성 검사 도구 활용

단순한 카운터 비교를 넘어 실제 저널 파일의 내부가 얼마나 망가졌는지 검증하려면 브로커가 제공하는 로우레벨(Low-level) 툴을 사용해야 합니다.

  • Artemis의 경우: 브로커를 멈추고 터미널에서 artemis data print 명령을 실행합니다. 이 도구는 저널 파일의 레코드를 처음부터 끝까지 스캔하며, 고아 레코드(Orphaned records)나 깨진 데이터 블록이 있는지 텍스트 형태로 리포팅해 줍니다.
  • 이 과정을 통해 "메모리는 A 메시지가 있다고 주장하지만, 실제 저널 스캔 결과 A 메시지의 본문이 유실되었다"는 사실을 확정 지을 수 있습니다.

4. 아키텍처 복원 전략: 강제 동기화(Rebuild)

불일치가 확정되었다면, 오염된 메모리 상태를 버리고 디스크에 남아있는 진실을 바탕으로 메모리를 재건축해야 합니다.

A. 인덱스 재생성 (Index Rebuild)
KahaDB 환경에서 가장 강력하고 확실한 복구법입니다. 브로커를 안전하게 종료한 뒤, KahaDB 데이터 폴더 내부의 db.data 파일(B-Tree 인덱스)과 db.redo.log 파일을 수동으로 삭제(또는 백업 이동)합니다.
이후 브로커를 재시작하면, 브로커는 인덱스가 없음을 감지하고 남겨진 db-*.log 파일들을 처음부터 끝까지 풀 스캔(Full Scan)하여 메모리의 큐 카운터와 B-Tree를 100% 디스크의 실제 데이터에 맞추어 새로 조립합니다.

B. 무결성 최우선 설정 도입
재발을 막기 위해 브로커 설정을 보수적으로 변경해야 합니다. OS의 캐시를 믿지 않도록 enableJournalDiskSyncs="true"를 강제하고, JVM의 힙 메모리를 충분히 확보하여 OOM으로 인한 강제 종료를 원천 차단하는 것이 핵심입니다.


결론적으로 브로커의 'In-memory State'와 'Storage' 간의 불일치는 고성능을 추구하는 분산 비동기 시스템이 떠안아야 할 숙명과도 같은 리스크입니다. 장애의 전조 증상을 빠르게 캐치하고, 제공되는 CLI 툴과 인덱스 재생성 기법을 통해 시스템의 진실을 디스크 기준으로 신속하게 재정렬하는 결단력이 필요합니다.

반응형