[Q]
해당 내용을 분석하여 apache kafka 에서 topic메시지를 백업하고 다시 복구할 수 있는 방법이 있는지 알려주세요. 혹은 server.properties 에서 retention을 변경 후 kafka를 재실행하면 topic에 처리되지 않은 메시지들이 남아 있고 처리될 수 있는지 확인해 주세요.
[A]
### 질문 요약
– Apache Kafka에서 토픽 메시지를 “백업 후 복구”하는 실무적인 방법이 있는지
– server.properties에서 보존 기간(retention)을 변경하고 브로커를 재시작하면, 기존에 처리되지 않은 메시지가 남아서 계속 소비(처리)될 수 있는지
### 1) Kafka 토픽 메시지 “백업-복구” 방법
Kafka는 기본적으로 데이터베이스처럼 내장된 백업/복구 기능을 제공하지 않습니다. 대신 운영 관점에서 아래와 같은 실전 옵션들이 사용됩니다.
– MirrorMaker 2 또는 Cluster Linking을 이용한 실시간 이중화
– 목적: 다른 클러스터로 토픽을 미러링하여 장애 시 복구
– 장점: 지속적 동기화, 장애 전환/복구 시 유용
– 고려: 네이밍, ACL, 오프셋 동기화, 압축/압축 해제 비용
– Kafka Connect + S3/HDFS/GCS Sink로 아카이빙
– 목적: 토픽 데이터를 객체 스토리지나 HDFS에 지속적으로 적재(로그 아카이브)
– 복구 절차: 저장된 파일(예: S3의 Parquet/JSON/Avro)을 Replayer(커스텀 앱 또는 Kafka Connect Source)로 읽어 신규 토픽에 재주입
– 장점: 장기 보관, 컴플라이언스 대응
– 고려: 스키마 호환성, 순서 보장(파티션 단위), 재주입 시 중복 처리 전략
– Filesystem 스냅샷(브로커 데이터 디렉터리) 기반 백업
– 목적: 브로커 호스트의 로그 디렉터리를 파일 단위로 스냅샷
– 복구 절차: 동일한 브로커/클러스터 토폴로지와 토픽 메타정보(파티션/리플리카)를 맞춰 복원
– 장점: 오프라인 전체 복구
– 고려: 클러스터 메타데이터 일관성(ZooKeeper or KRaft), 브로커 ID, topicId 불일치 리스크가 커서 신중한 운영 절차 필요
– Dead-letter 토픽(DLT) + 리플레이 전략
– 목적: 처리 실패 레코드 격리 및 재처리
– 방법: 소비 측에서 실패 레코드를 DLT로 보내고, 사후에 DLT를 소스 삼아 재소비
– 장점: 애플리케이션 레벨에서 명확한 재처리 경로
– 고려: 스키마/버전 호환, 멱등 설계
참고로 Spring Kafka를 사용한다면, 역직렬화 실패 등 문제 레코드를 자동으로 DLT에 퍼블리시하는 구성(RecoveringDeserializationExceptionHandler + DeadLetterPublishingRecoverer)으로 “실패 데이터 보존 및 재처리” 패턴을 손쉽게 운영할 수 있습니다. [[2]](about:blank) [[4]](about:blank) [[5]](about:blank) [[9]](about:blank) [[10]](about:blank)
### 2) retention 변경 + 브로커 재시작 시, 미처리 메시지의 보존/소비 가능성
– retention.ms/retention.bytes는 “로그 세그먼트 삭제 시점/크기 기준”을 바꿉니다. 이 설정은 메시지 삭제 정책이며, “이미 존재하는 미처리 메시지를 즉시 삭제하지는 않습니다.”
– 따라서 보존 기간을 늘리면, 해당 기준에 따라 세그먼트가 더 오래 유지되고, 컨슈머 그룹의 커밋 오프셋이 메시지 뒤에 있다면 컨슈머는 재시작 후에도 남아 있는 미처리 메시지를 계속 소비할 수 있습니다.
– 반대로 보존 기간을 크게 줄이거나, compact+delete 혼합 정책에서 delete가 유효한 상황이면, 오래된 세그먼트는 삭제되어 미처리라 하더라도 사라질 수 있습니다. 이 경우 컨슈머는 더 이상 해당 오프셋을 읽을 수 없고, “오프셋 초과(OutOfRange) → auto.offset.reset 정책(earliest/latest) 적용” 흐름이 발생합니다.
– 요약하면:
– 보존 기간을 늘리면: “미처리 메시지”가 남아 계속 소비될 가능성이 높아집니다.
– 보존 기간을 줄이면: 삭제가 더 빨라져 “미처리 메시지”가 사라질 수 있습니다.
– 브로커 재시작 자체는 미처리 메시지의 보존 여부를 바꾸지 않습니다. 삭제 정책(보존 설정)과 로그 청소 스케줄이 핵심입니다.
Spring Kafka 환경이라면, 컨슈머의 재처리/복구 전략으로 아래 기능들이 실무적으로 유용합니다.
– DeadLetterPublishingRecoverer: 실패 레코드를 DLT로 보관, 사후 재처리 파이프라인 구축 [[5]](about:blank)
– SeekToCurrentErrorHandler/AfterRollbackProcessor: 반복 실패 레코드 스킵 및 DLT 퍼블리시 설정 가능 [[5]](about:blank)
– Streams 측 RecoveringDeserializationExceptionHandler: 역직렬화 오류 발생 시 DLT로 복구 가능 [[2]](about:blank) [[9]](about:blank)
### 3) 권장 운영 시나리오(실무 팁)
– 장애 복구 목적: MirrorMaker 2/Cluster Linking으로 이중화 + 오브젝트 스토리지 아카이빙을 병행해 “즉시 서비스 복구”와 “장기 원본 보존”을 분리
– 재처리 목적: DLT를 표준화하고, 재주입(Replayer) 경로를 자동화
– 데이터 유실 방지: 중요한 토픽은 retention.ms를 충분히 길게 설정하고, min.cleanable.dirty.ratio/segment.ms 등 로그 압축/삭제 설정을 보수적으로 운용
– 컨슈머 전략: 멱등/중복 허용 처리, 오프셋 커밋 정책(수동 커밋/배치 커밋) 명확화, auto.offset.reset=earliest를 필요 시 활용
– 변경 테스트: 운영 전 스테이징에서 retention 조정 → 세그먼트 삭제 타이밍 확인 → 컨슈머 재시작 후 소비 흐름 검증
### 4) 결론
– “백업-복구”는 내장 기능이 아니라, 미러링/아카이빙/파일 스냅샷/DTL 리플레이 등의 운영 패턴으로 구현합니다.
– retention 값을 변경하고 브로커를 재시작해도, 삭제 조건이 충족되지 않았다면 미처리 메시지는 그대로 남고 컨슈머가 이어서 처리할 수 있습니다. 다만 보존 기간을 줄이면 미처리 메시지가 삭제될 수 있으니 주의가 필요합니다.
– Spring Kafka를 사용 중이라면 DLT 및 복구 핸들러 구성이 재처리 안정성을 크게 높여줍니다. [[2]](about:blank) [[4]](about:blank) [[5]](about:blank) [[9]](about:blank) [[10]](about:blank)