(kafka) debezium을 사용한 exactly once producing

2025. 4. 21. 22:37개발 지식

반응형

Abstract

마이크로서비스 아키텍처(MSA) 환경에서 서비스 간 메시지 전송의 정합성을 확보하는 일은 매우 중요한 과제입니다.
일반적인 Kafka acks 설정만으로는 메시지 중복 전송 방지나 전송과 오프셋 커밋의 원자성을 동시에 만족시키기 어렵습니다.
 
이 글에서는 enable.idempotence와 transactional.id 기능을 활용해 브로커 단계에서 exactly‑once producing을 완전하게 확보하는 방법을 설명합니다. 아울러 Debezium을 통한 DB CDC(Change Data Capture)와 Kafka Connect/Connector 구조를 결합하여, 외부 데이터베이스 트랜잭션과 Kafka 메시지 전송 간의 일관성을 유지하면서도 높은 확장성과 운영 편의성을 제공하는 방안을 살펴봅니다.
 

1. 서론

MSA 환경에서는 각기 다른 서비스 간에 전달되는 메시지가 한 번만 정확히 처리되어야만 전체 시스템의 정합성을 유지할 수 경우가 많습니다. 하지만 메시지를 수신한 쪽에서 부수효과가 발생하는 경우에는 트랜잭션 롤백이 불가능해 exactly‑once processing을 보장한다는 것은 현실적으로 거의 달성하기 어려운 문제입니다. 반면, exactly‑once producing은 브로커가 제공하는 멱등성(idempotence)과 트랜잭션(transaction) 기능을 적절히 결합하면 완전하게 확보할 수 있습니다.
 
이 글에서는 먼저 Kafka 프로듀서-브로커 간의 기본 acks 설정이 지닌 내구성과 가용성 사이의 트레이드오프를 살펴보고, 각각의 한계를 짚어봅니다. 이어서 enable.idempotence=true를 통해 파티션 경계 내 중복 전송을 제거하고, transactional.id=<고유ID>를 통해 메시지 전송과 오프셋 커밋을 하나의 트랜잭션으로 묶어 처리하는 과정을 상세히 기술합니다. 마지막으로 Debezium 기반 CDC와 Kafka Connect/Connector 조합을 통해 외부 RDBMS 트랜잭션과의 일관성을 유지하면서도 무중단 수평 확장과 운영 편의성을 확보하는 구조를 소개합니다.
 

2. 기본 Producer·Broker 설정의 한계

Apache Kafka는 acks 설정(acks=0, acks=1, acks=all)으로 프로듀서가 브로커로부터 얼마나 많은 확인을 기다릴지를 제어합니다.
하지만 이들 옵션만으로는 메시지를 반드시 한 번만 기록하고, 전송과 오프셋 커밋을 원자적으로 묶는 동작을 모두 보장할 수 없습니다.
 
acks=0 모드는 브로커로부터 ACK를 전혀 기다리지 않고 즉시 성공으로 간주하므로, 초저지연을 얻을 수 있으나 네트워크 분리나 브로커 장애 시 메시지가 한 번도 기록되지 않을 수 있습니다.
 
acks=1 모드는 리더 파티션에 메시지가 기록된 후에만 ACK를 반환하므로 리더 도달을 보장하지만, 팔로워 복제 지연이나 리더 장애로 인해 ISR(In‑Sync Replicas)에 복제되지 않은 메시지가 유실될 위험이 남습니다.
 
acks=all에 min.insync.replicas ≥ 2를 결합하면 복제본이 반드시 충분히 살아 있어야만 쓰기를 허용해 데이터 유실 가능성을 사실상 제거하지만, 복제본 하나만 빠져도 서비스 전체의 쓰기가 중단될 수 있어 가용성이 크게 저하될 수 있습니다.
 
또한 프로듀서-브로커 단계의 내구성이 아무리 높아도, 컨슈머가 메시지를 처리한 뒤 오프셋을 커밋하는 구조에서는 처리 도중 장애가 발생하면 동일 메시지를 재처리하거나 아예 처리되지 않은 채 넘어가는 상황이 남아 있습니다. 이처럼 기본 acks 설정만으로는 중복 전송 방지전송·커밋 원자성을 동시에 달성하지 못합니다.
 

3. Kafka의 Exactly‑Once Producing 메커니즘

Kafka 브로커 단계에서 exactly‑once producing을 달성하기 위해서는 멱등성(idempotence)과 트랜잭션(transaction) 기능을 결합해야 합니다.
 
첫째, Idempotent Producer는 enable.idempotence=true 설정을 통해 활성화됩니다. 프로듀서 인스턴스마다 부여된 Producer ID와 각 파티션 메시지에 할당된 Sequence Number를 조합하여, 브로커는 (Producer ID, Partition, Sequence Number)가 이미 처리된 메시지를 중복으로 식별하고 폐기(drop)합니다.
 
이로써 파티션 경계 내에서 네트워크 재시도나 클라이언트 중복 호출로 인한 중복 전송을 전면 차단할 수 있습니다.
 
둘째, Transactional Producer는 여기에 transactional.id=<고유ID>를 추가하여 구현됩니다. 트랜잭션 프로듀서는 다음과 같은 순서로 동작합니다.

  1. initTransactions() 호출을 통해 과거 트랜잭션 상태를 복원하고,
  2. beginTransaction()으로 트랜잭션을 시작한 뒤,
  3. send(...) 메서드로 여러 파티션·토픽에 메시지를 전송하고,
  4. sendOffsetsToTransaction(...)를 통해 컨슈머 오프셋을 동일 트랜잭션에 포함시킨 다음,
  5. commitTransaction() 또는 장애 시 abortTransaction()을 호출합니다.

이 과정에서 Transaction Coordinator는 __transaction_state 내부 토픽에 트랜잭션 상태를 내구성 있게 기록하며, 네트워크 타임아웃이나 GC pause 같은 장애가 발생해도 정확히 복원하여 중복 커밋을 방지합니다.
 
특징

  • 파티션 단위 네트워크 중복 방지
  • 메시지 전송과 오프셋 커밋의 원자적 묶음
  • 장애 복구 시 이전 트랜잭션 상태 안전 재개

 
이 두 기능을 결합하면 Kafka 브로커 단계에서 중복 없이 단 한 번만 메시지를 기록하고, 컨슈머 재시작 시에도 전송과 오프셋 커밋이 함께 보장되는 exactly‑once producing이 완전하게 확보됩니다.
 

4. Debezium + Kafka Connect/Connector를 통한 확장

외부 RDBMS의 트랜잭션 커밋 시점과 Kafka 메시지 전송 시점을 일치시키려면, Debezium 기반 CDC와 Kafka Connect/Connector 구조가 유용합니다.
 
Debezium은 데이터베이스의 Write‑Ahead Log(WAL) 를 직접 추출(tailing)하여, 먼저 전체 테이블을 스냅샷으로 덤프한 뒤 이후 변경 로그를 연속 전송합니다. 이때 Kafka Connect는 Debezium Connector를 통해 poll() 메서드로 변경 로그를 읽어 enable.idempotence와 transactional.id가 활성화된 Producer로 exactly‑once producing을 수행하며, WAL LSN(Log Sequence Number) 을 Kafka Connect offset에 기록합니다.
 
장애가 발생해도 커밋되지 않은 LSN(Log Sequence Number)부터 재시작하기 때문에 메시지가 중복 전송되지 않습니다. Kafka Connect 플랫폼은 Distributed Mode로 여러 Worker에 Task를 자동 분배·재할당하므로, 무중단 수평 확장과 고가용성을 확보할 수 있습니다. Connector 설정과 offset이 Kafka 토픽에 보관되므로 Worker를 교체하거나 재배포해도 별도 상태 이관 없이 즉시 복구됩니다.
 

5. 결론

MSA 환경에서 exactly‑once producing을 달성하려면, Kafka 브로커의 기본 acks 설정만으로는 부족하며, 멱등성(idempotence)과 트랜잭션(transaction) 기능을 결합해야 합니다. enable.idempotence=true로 중복 전송을 차단하고, transactional.id=<고유ID>로 메시지 전송과 오프셋 커밋을 원자적으로 묶으면 브로커 단계에서 정확히 한 번만 메시지를 기록할 수 있습니다.
 
더 나아가 Debezium CDC와 Kafka Connect/Connector 구조를 적용하면 외부 데이터베이스 트랜잭션과 Kafka 메시지 전송 간의 일관성을 유지하면서도 높은 확장성과 운영 편의성을 누릴 수 있습니다. 이와 같은 구조는 MSA 기반 서비스에서 메시지 생산의 중복·유실 문제를 근본적으로 해소하고, 서비스 안정성 및 사용자 경험을 크게 향상시킵니다.

반응형