← 학습 카테고리

Learn

Kafka

84개 모듈 · 현재 79번째

Kafka 모듈 79/84 kafka-learn-79

트랜잭션 컨트롤 레코드 — 로그 안에 새겨지는 COMMIT/ABORT 마커

Kafka 트랜잭션 컨트롤 레코드 및 ConsumerRebalanceListener#onPartitionsLost(KIP-429) 공식 문서 종합 (웹 리서치, 2026) — Apache Kafka 공식 문서·기술 블로그(Kafka Transactions Deep Dive), KIP-429: Kafka Consumer Incremental Rebalance Protocol Kafka Transactions Deep Dive 기술 블로그

이 모듈을 다 읽으면

  • kafka-learn-35의 read_committed가 실제로는 로그에 새겨진 컨트롤 레코드를 보고 필터링한다는 것을 설명할 수 있다
  • 컨트롤 레코드가 오프셋을 차지하면서도 애플리케이션에는 절대 전달되지 않는다는 것과, 그로 인한 '오프셋 구멍' 현상을 설명할 수 있다

kafka-learn-35에서 다룬 read_committed(커밋된 트랜잭션의 레코드만 보이게 함)를 전제로, 그 필터링이 실제로 로그 안의 어떤 물리적 표식(컨트롤 레코드)을 보고 이뤄지는지를 정리한다.

COMMIT/ABORT 마커 — 트랜잭션 경계를 로그에 직접 새긴다

Kafka는 트랜잭션이 끝날 때 그 경계를 알리는 특수한 컨트롤 메시지(COMMIT 마커 또는 ABORT 마커)를 해당 파티션에 실제로 써넣는다 — 이는 애플리케이션이 만든 일반 레코드가 아니라 브로커가 직접 기록하는 메타 레코드다. 트랜잭셔널 메시지를 포함한 파티션에는 그 트랜잭션이 성공(commit)했는지 취소(abort)됐는지를 나타내는 이 마커가 함께 들어있다 — 이 마커도 로그 안에서 오프셋 하나를 정식으로 차지한다.

핵심 포인트

  • 트랜잭션이 끝날 때 브로커가 COMMIT 또는 ABORT 마커를 그 파티션에 직접 기록 — 애플리케이션 레코드가 아니라 메타 레코드
  • 이 마커도 로그 안에서 정식 오프셋 하나를 차지함

이 마커를 보고 read_committed가 실제로 필터링한다

kafka-learn-35에서 다룬 isolation.level=read_committed 컨슈머는 LSO(Last Stable Offset — 아직 진행 중이거나 아직 완결 안 된 트랜잭션이 없는, 안전하게 읽을 수 있는 지점)까지만 읽고, 그 안에서 ABORT 마커가 붙은 트랜잭션의 레코드는 걸러낸다 — 즉 이 필터링이 실제로 근거하는 것이 바로 이 컨트롤 레코드다. 반면 이 마커 자체는 read_committed든 read_uncommitted든 어느 격리 수준에서도 애플리케이션에 직접 전달되지 않는다.

핵심 포인트

  • read_committed 컨슈머는 LSO까지만 읽고, ABORT 마커가 붙은 트랜잭션의 레코드를 걸러냄 — 이 필터링의 근거가 바로 컨트롤 레코드
  • 컨트롤 레코드 자체는 read_committed·read_uncommitted 어느 격리 수준에서도 애플리케이션에 직접 전달 안 됨

그 결과 — 컨슈머가 보는 오프셋에 '구멍'이 생긴다

컨트롤 레코드는 오프셋을 차지하지만 애플리케이션에는 절대 전달되지 않으므로, 트랜잭셔널 메시지가 있는 토픽을 읽는 애플리케이션은 소비한 오프셋 시퀀스에서 군데군데 빠진 번호(구멍)를 보게 된다. read_committed 컨슈머라면 여기에 더해 ABORT된 트랜잭션의 레코드까지도 (유효한 오프셋을 가졌음에도) 전달되지 않아 구멍이 하나 더 생긴다. 즉 '레코드 번호가 연속적이지 않은 게 정상'이라는 걸 알아야 오프셋 시퀀스를 보고 데이터 유실을 오판하지 않는다.

핵심 포인트

  • 컨트롤 레코드는 오프셋을 차지하지만 전달 안 됨 → 소비 오프셋 시퀀스에 구멍이 생김(정상 현상)
  • read_committed에서는 ABORT된 트랜잭션의 유효 오프셋 레코드도 전달 안 돼 구멍이 하나 더 생김 — 오프셋 불연속을 유실로 오판하면 안 됨