"Kafka는 exactly-once인가요" — 질문이 틀렸다
"Kafka는 exactly-once를 보장하나요?" — Kafka를 배우면 누구나 받는 질문이다. 답은 "무엇의 exactly-once인지에 따라 다르다"다. 단일 partition 쓰기(idempotent)는 exactly-once다. consume-process-produce 패턴(EOS)도 exactly-once다. 하지만 시스템 외부(DB)까지는 아니다. 이 질문이 틀린 이유는 "exactly-once"를 메시지 자체의 마법 같은 속성으로 생각하기 때문이다. 실제로는 "출력 메시지와 consumer offset을 한 트랜잭션으로 묶어 원자 commit"하는 설계 패턴의 결과다.
이 글은 Kafka의 세 가지 전달 보장 — at-most-once, at-least-once(기본), exactly-once — 의 정의, 달성 방법, 그리고 정확한 경계를 다룬다. 중복을 그냥 두면 결제가 두 번 일어나고, 손실을 그냥 두면 주문이 사라진다. 전달 보장의 경계를 정확히 아는 것이 신뢰성 설계의 출발점이다.
세 가지 전달 보장 — 중복과 손실의 트레이드오프
택배에 비유하면 감이 온다:
- at-most-once: 문 앞에 두고 간다(비가 와도 책임 안 짐). 잃을 수 있지만 중복은 안 된다.
- at-least-once: 수령증 받을 때까지 다시 온다. 같은 소포가 두 번 올 수 있다(중복).
- exactly-once: 수령증(출력 메시지)과 배송 완료 등록(offset commit)을 한 장부에 동시에 적는다. 둘 중 하나만 일어나는 일은 없다.
| 보장 | 어떻게 | Kafka 구현 | 비용 |
|---|---|---|---|
| at-most-once | 확인 안 함, 재시도 안 함 | acks=0 |
최저 |
| at-least-once | 확인하고, 실패 시 재시도(중복 가능) | acks=all + 재시도, Kafka 기본 |
낮음 |
| exactly-once | 중복 제거 + 원자 쓰기 | idempotent producer + transactions + read_committed | 높음 |
Kafka의 전달 보장은 버전을 거치며 발전했다 (design.md — Message Delivery Semantics):
- 0.11 이전: producer는 at-least-once(네트워크 에러 시 재전송 → 중복 가능).
- 0.11.0.0부터: idempotent delivery(PID + sequence로 중복 제거) → 단일 partition exactly-once. transactions → 여러 partition 원자 쓰기.
전달 보장 발전사 — 타임라인으로 보는 진화
이 발전을 시간순으로 보면 각 단계가 "이전의 어떤 갭을 메웠는지" 보인다:
flowchart LR
A["0.11 이전<br/>at-least-once만<br/>(중복 가능)"] --> B["0.11 (2017)<br/>idempotent producer<br/>(단일 partition 중복 제거)"]
B --> C["0.11<br/>transactions<br/>(여러 partition 원자)"]
C --> D["2.5+<br/>exactly_once_v2 (KIP-447)<br/>(consume-process-produce EOS)"]
D --> E["3.0+<br/>idempotence 기본 true"]
E --> F["4.x<br/>KRaft + EOS 안정화"]| 단계 | 해결한 갭 | 남은 한계 |
|---|---|---|
| at-least-once | (기준선) | 중복 |
| idempotent producer | 단일 partition 중복 | 여러 partition은 미지원 |
| transactions | 여러 partition 원자 | consumer offset과 결합은 별도 |
| EOS v2 | consume-process-produce 원자 | 외부 시스템은 미지원, 성능 비용 |
이 타임라인이 "Kafka는 exactly-once인가"라는 질문이 왜 범위를 정해야 하는지 보여준다 — "exactly-once"가 버전마다 의미하는 바가 달랐고, 각 단계가 좁은 범위의 정확성을 추가해왔다. 4.x의 EOS도 "같은 클러스터 내 consume-process-produce"에 한정된다.
exactly-once의 정확한 범위 — 오해 주의
"exactly-once"가 어디까지 보장인지를 정확히 해야 한다:
- 단일 partition 쓰기: idempotent producer로 exactly-once(장 03). 4.x에선 기본 동작.
- consume-process-produce(consumer가 읽고 처리하고 다른 topic에 쓰는 패턴): EOS(Exactly-Once Semantics). 출력 메시지 + 입력 offset을 같은 트랜잭션으로 묶어 commit.
- 시스템 외부(DB 등): Kafka만으로는 보장 못 함. 외부 시스템도 트랜잭션 참여 또는 멱등 처리 필요.
"Kafka는 exactly-once인가"가 틀린 질문인 이유 — 범위를 안 정하고 묻기 때문. 단일 partition 쓰기는 이미 exactly-once(4.x 기본), consume-process-produce는 EOS로 가능, DB 쓰기는 불가.
EOS — consume-process-produce에서 exactly-once가 어떻게 나오나
여기서 핵심 질문: consume-process-produce에서 "출력과 offset을 한 트랜잭션으로"가 왜 exactly-once를 만드는가?
exactly-once는 메시지 자체의 마법 같은 속성이 아니다. "출력 메시지가 commit됐으면 입력 offset도 commit됐고, 입력 offset이 commit됐으면 출력도 commit됐다"는 원자성에서 나온다. 둘 중 하나만 일어나는 상태를 원천 차단한다.
EOS의 세 기둥
- consumer partition 배타 소유: 한 consumer group 내 partition은 한 consumer만(장 05). 같은 입력을 두 consumer가 동시에 처리하는 일 없음.
- producer 트랜잭션: 출력 record 생산 + consumer offsets 갱신을 하나의 트랜잭션으로 원자 commit.
- consumer마다 producer 1개: rebalance 시 소유권 이전을 정확히 처리.
consume-process-produce 흐름
sequenceDiagram
participant C as consumer (read_committed)
participant T as transaction
participant O as output topic
participant OS as __consumer_offsets
C->>C: poll() → records
C->>T: beginTransaction()
C->>O: send(출력 메시지들)
C->>OS: sendOffsetsToTransaction(offsets, groupMetadata)
C->>T: commitTransaction() // 출력과 offset이 원자적으로 commit
Note over O,OS: 둘 다 commit 되거나 둘 다 abort — 중간 상태 없음코드 패턴 (ExactlyOnceMessageProcessor.java):
producer.initTransactions(); // 좀비 차단
consumer.subscribe(...);
while (running) {
records = consumer.poll(...);
producer.beginTransaction();
for (record : records) producer.send(transform(record));
producer.sendOffsetsToTransaction(offsets, consumer.groupMetadata());
producer.commitTransaction(); // 원자 commit
}좀비 차단 — transactional.id가 왜 필요한가
producer가 크래시 났는데 사실은 살아있어서(좀비) 같은 데이터를 다시 쓰면 중복이 생긴다. 이걸 막는 것이 transactional.id다:
initTransactions()시 broker가 이transactional.id의 epoch를 올린다.- 이전 epoch(좀비)의 producer가 쓰려 하면
ProducerFencedException→ 좀비 격리. - 이것이 "재시작해도 안전"을 보장하는 핵심.
transactional.id는 안정적이고 고유해야 한다 — 재시작해도 같은 값이 유지되어야 좀비 차단이 작동한다. 아무 값이나 쓰면 안 된다.
isolation.level=read_committed — abort된 트랜잭션을 안 보게
EOS consumer는 isolation.level=read_committed를 써야 한다:
- consumer가 commit된 트랜잭션만 읽는다. abort된 것은 보이지 않는다.
- EOS에서 offset은 트랜잭션으로 commit되므로
enable.auto.commit=false필수(자동 commit이 트랜잭션을 우회하면 안 됨).
read_committed는 성능에 영향이 있다 — abort 처리·LISO(last stable offset) 추적으로 지연이 생긴다. 필요한 곳에만 쓴다.
LSO(last stable offset) — read_committed가 멈추는 지점
read_committed consumer는 LSO(last stable offset)까지만 읽을 수 있다. LSO는 "아직 진행 중이거나 abort 안 된 가장 오래된 트랜잭션의 시작점" 전까지다. 즉, 한 트랜잭션이 진행 중이면 그 이후의 commit된 메시지도 consumer는 LSO 때문에 못 본다(잠시 대기).
왜 이렇게까지 하는가 — abort될 수 있는 트랜잭션의 데이터를 consumer에게 보였다가 나중에 "사실 취소"할 수 없기 때문. LSO는 "이 지점까지는 모든 트랜잭션이 결정났다(또는 abort 처리됐다)"는 안전 경계다. 장기 실행 트랜잭션이 LSO를 멈추게 하므로(지연 유발), transaction.timeout.ms로 트랜잭션 시간 상한을 둬야 한다 — 안 두면 하나의 느린 트랜잭션이 전체 consumer 지연을 만든다.
EOS 실패 모드 — 트랜잭션 중간에 크래시 나면?
EOS의 진짜 가치는 실패 상황에서 정확성을 유지하는 데 있다. consumer가 트랜잭션 중간에 크래시 나는 시나리오를 보자:
flowchart TD
A["beginTransaction"] --> B["send(출력들)"]
B --> C["sendOffsetsToTransaction"]
C --> D{"commitTransaction 도달?"}
D -->|O 크래시 전| E["트랜잭션 미완료 → abort 타임아웃 → 출력 안 보임(read_committed)"]
D -->|O commit 직후 크래시| F["commit 성공 → 출력+offset 영속 → 재시작 시 다음부터"]
E --> G["재시작: offset 안 넘어감 → 입력 재처리(at-least-once) → EOS 보장"]핵심: 트랜잭션이 commit되지 않고 끝나면(크래시·타임아웃) broker가 그 트랜잭션을 abort로 처리 → 출력 메시지는 read_committed consumer에게 안 보인다 → 마치 처음부터 없었던 것처럼. consumer offset도 commit 안 됐으므로, 재시작 시 같은 입력을 다시 처리한다(at-least-once 재시도). 결국 "모두 일어나거나 아무것도 안 일어나거나"가 보장된다.
transaction.timeout.ms — 좀비·지연 방지
트랜잭션에 시간 상한(transaction.timeout.ms, 기본 60초)을 둔다:
- producer가 이 시간 내에 commit/abort 안 하면 broker가 강제 abort → 장기 미완료 트랜잭션이 LSO를 멈추게 하는 걸 방지.
- 좀비 producer도 같은 원리로 차단 —
transactional.id의 epoch가 올라가면 옛 epoch의 트랜잭션은 abort.
좀비 차단 worked example — zombie fencing이 어떻게 동작하는가
좀비 시나리오를 구체적으로 보자. producer P1(transactional.id=order-processor-1)이 트랜잭션 도중 네트워크 분단으로 "죽은 줄 알았는데 살아있다(좀비)". 한편 같은 transactional.id를 가진 P1'가 재시작됐다:
P1'가initTransactions()호출 → broker가order-processor-1의 epoch를 5→6으로 올림.- 좀비
P1(epoch=5)이 늦게 commit 시도 → broker가ProducerFencedException발생 →P1격리. P1'(epoch=6)만 정상 동작 → 같은 데이터 두 번 쓰는 일 차단.
이게 transactional.id가 "안정적이고 고유"해야 하는 이유다 — 같은 논리 역할(예: order-processor-1)의 재시작은 같은 id를 써야 좀비가 잡힌다. 반대로 서로 다른 역할이 같은 id를 쓰면 서로를 fence해버리는 사고가 난다. 운영에선 id 할당 체계를 명확히 설계해야 한다.
at-least-once vs exactly-once — 비용 비교
"왜 모든 곳에 EOS를 안 쓰나" — 비용 때문이다. 두 보장의 실사용 비교:
| 항목 | at-least-once (acks=all+재시도) |
EOS (transactional + read_committed) |
|---|---|---|
| 처리량 | 높음 | 낮음(트랜잭션 오버헤드 10 ~ 20%+ 추정, 환경 의존) |
| 지연 | 낮음 | 높음(LSO 대기·commit 비용) |
| 구현 복잡도 | 낮음(재시도만) | 높음(transactional API·좀비 처리) |
| 중복 가능성 | 있음(애플리케이션 멱등 설계로 완화) | 없음(단일 클러스터 내) |
| 적합 | 로그·메트릭·멱등 처리 가능한 곳 | 결제·주문·정확성 필수 |
그래서 "무조건 EOS"가 정답이 아니다. 애플리케이션이 멱등 처리(DB upsert 등)로 at-least-once 중복을 흡수할 수 있으면, at-least-once가 훨씬 싸다. EOS는 정말 "정확히 한 번"이 요구되는 좁은 영역(결제·원장)에 쓴다.
전달 보장 결정 트리 — 어느 보장을 택할까
실제 설계에서 "우리는 뭘 써야 하나"를 결정하는 흐름:
flowchart TD
Q1{데이터 손실 허용?} -->|O| AMO["at-most-once (acks=0)"]
Q1 -->|X| Q2{"중복 처리가 안전한가?<br/>(멱등/DB upsert 가능?)"}
Q2 -->|O| ALO["at-least-once (acks=all+재시도)<br/>+ 애플리케이션 멱등"]
Q2 -->|X| Q3{"consume-process-produce 패턴?<br/>같은 Kafka 클러스터 내?"}
Q3 -->|O| EOS["EOS (transactional + read_committed)"]
Q3 -->|X 외부 DB/HTTP| OUTBOX["at-least-once + outbox/멱등 키 패턴<br/>(Kafka만으로는 한계)"]이 트리가 보여주는 핵심: exactly-once는 항상 정답이 아니다. 손실을 감내하면 at-most-once(로그), 중복을 애플리케이션이 흡수하면 at-least-once, consume-process-produce면 EOS, 외부 시스템이면 outbox 패턴. 각기 비용·복잡도가 다르다.
외부 시스템까지 exactly-once — outbox 패턴
Kafka 트랜잭션은 같은 클러스터 내만 보장한다. "메시지 처리 후 DB에 쓰기"처럼 외부 DB까지 정확히 한 번이 필요하면, Kafka 트랜잭션이 DB를 묶을 수 없으므로 별도 패턴이 필요하다.
대표적 해법 — transactional outbox:
- 비즈니스 로직이 DB에 "보낼 메시지"를 outbox 테이블에 같은 DB 트랜잭션으로 쓴다(비즈니스 데이터 + outbox가 원자).
- 별도 프로세스(또는 Debezium CDC)가 outbox 테이블을 읽어 Kafka로 produce.
- produce 성공하면 outbox 행을 삭제/마킹.
이렇게 하면 "DB 쓰기 + Kafka produce"가 (outbox를 매개로) 원자가 된다. 핵심은 DB 트랜잭션과 Kafka 트랜잭션을 직접 묶지 않고, outbox라는 중간 매개로 우회하는 것. 반대 방향(Kafka → DB)은 consumer가 DB에 멱등 쓰기(중복 키 허용)로 at-least-once 중복을 흡수한다.
이 패턴이 Kafka "exactly-once"의 경계를 보여준다 — 클러스터 내는 EOS, 외부는 설계 패턴으로 보완해야 한다.
Kafka Streams가 EOS를 "자동"으로 만드는 것
EOS를 직접 구현하려면 transactional API(initTransactions/beginTransaction/sendOffsetsToTransaction/commitTransaction)를 다뤄야 한다. 복잡하고 실수하기 쉽다. Kafka Streams는 이걸 프레임워크가 자동 처리한다 — processing.guarantee=exactly_once_v2 한 줄이면:
- 내부적으로 transactional producer + read_committed consumer + offset 원자 commit을 자동 구성.
- rebalance 시 트랜잭션 정리도 자동.
- 개발자는 topology 로직만 짠다.
이게 Streams가 EOS를 쓰는 애플리케이션에서 인기인 핵심 이유다 — 직접 트랜잭션 API를 다루는 복잡도를 프레임워크가 흡수한다. 단, exactly_once (v1, KIP-98)은 폐지됐고 exactly_once_v2 (KIP-447, 2.5+)를 써야 한다 — 구형 자료 주의.
전달 보장 관련 자주 묻는 추가 질문
| 질문 | 답 |
|---|---|
| "read_committed가 처리량을 얼마나 깎나" | LSO 대기·abort 처리로 지연. 정량값은 환경 의존(미검증), 보통 수 ~ 10%+ |
| "EOS 없이 consume-process-produce 정확성?" | at-least-once만 → 중복 발생. 애플리케이션 멱등으로 보완하거나 EOS 써야 |
| "transactional.id를 바꾸면?" | 다른 producer로 인식 → 좀비 차단 안 됨. 재시작은 같은 id 유지 필수 |
| "EOS consumer와 일반 consumer 혼합?" | read_committed consumer만 abort 제외. 일반(read_uncommitted)은 abort된 것도 봄 |
| "외부 DB 쓰기까지 EOS?" | 불가(outbox 패턴 등 별도 설계). Kafka 클러스터 내 한정 |
Kafka 4.3 실습 — 직접 확인하기
사전: KRaft 단일 노드. EOS는 트랜잭션 API 코드가 필요 → console 도구로 완전 재현은 어렵다(미검증: console 한계).
transaction 상태 관찰
# Kafka 4.3 — 트랜잭션 내부 topic 확인(구조적)
bin/kafka-topics.sh --list --bootstrap-server localhost:9092
# __transaction_state 가 보임 (트랜잭션 상태 저장, compact 정책)확인할 것: __transaction_state 내부 topic 존재(트랜잭션 로그). EOS 앱 기동 후 이 topic에 상태가 쓰인다.
완전한 EOS 검증(출력+offset 원자성)은 두 터미널에 producer/consumer + ExactlyOnceMessageProcessor 예제를 실행해야 한다. 본 노트에선 개념·내부 topic 확인으로 한계 명시. idempotence 효과(중복 제거) 시각화도 broker 재시작·네트워크 에러 시뮬레이션이 필요해 console 도구로는 어렵다.
EOS 검증 — 무엇을 어떻게 확인하는가
EOS가 진짜 동작하는지 검증하려면 고의 장애 주입이 필요하다. 절차(개념):
- 환경:
ExactlyOnceMessageProcessor예제 기동(input topic → 처리 → output topic,transactional.id설정). - 정상 처리 확인: input에 메시지 → output에 정확히 한 번 나타나는지 카운트.
- 장애 주입: 처리 중간에 consumer 프로세스 kill(트랜잭션 도중 크래시 시뮬레이션).
- 재시작 후 확인: 같은
transactional.id로 재기동. output에 중복 없이 이어지는지(abort된 미완료 트랜잭션의 출력이 안 보이는지). __transaction_state관찰: 트랜잭션 상태가 (Begin→PrepareCommit→Complete)로 전이하는지(구조적 확인).- read_committed vs read_uncommitted 대비: read_uncommitted consumer는 abort된 것도 보는지, read_committed는 안 보는지 교차 확인.
이 절차가 "출력+offset 원자 commit"이 실제로 중복·손실을 막는지 눈으로 확인하는 방법이다. 단, 단일 노드 + console 도구로는 3 ~ 4번(장애 주입·재시작)이 어려워 애플리케이션 코드가 필수다.
흔히 묻는 것, 흔히 틀리는 것
| 오해 | 정정 |
|---|---|
| "Kafka는 항상 exactly-once다" | 기본은 at-least-once. exactly-once는 idempotence/transactions 명시 적용 시 |
| "exactly-once는 메시지 속성이다" | 아님. 출력+offset 원자 commit이라는 설계 패턴의 결과 |
| "exactly-once가 DB 쓰기까지 보장한다" | Kafka 내부 한정. 외부 DB는 별도 트랜잭션/멱등 필요 |
| "idempotent producer = exactly-once" | 단일 partition에 한정. 여러 partition/offset은 transactions 필요 |
| "transactional.id는 아무 값이나 된다" | 안정적이고 고유해야. 좀비 차단의 기준 |
| "read_committed는 성능에 무관하다" | abort 처리·LISO 지연 있음. 필요 시만 |
| "exactly_once와 exactly_once_v2는 같다" | 구형(KIP-98)은 폐지, v2(KIP-447) 사용. 구형 자료 주의 |
| "transaction.timeout.ms는 안 설정해도 된다" | 장기 트랜잭션이 LSO를 멈춰 전체 consumer 지연 유발. 반드시 상한 설정 |
| "EOS를 쓰면 외부 DB도 자동 exactly-once" | 아니다. 클러스터 내 한정. 외부는 outbox/멱등 패턴 별도 필요 |
| "idempotent producer는 4.x에서도 켜야 한다" | 4.x 기본 true. 별도 지정 불필요(단, 구형 자료는 false 기준) |
더 깊이
- Kafka Streams의 EOS: Streams는 consume-process-produce를 프레임워크 수준에서 자동화한다.
processing.guarantee=exactly_once_v2(KIP-447, 2.5+)로 EOS 활성화 — 내부적으로 transactional producer + read_committed consumer + offset 원자 commit을 자동 처리. 개발자가 직접 트랜잭션 API를 다루지 않아도 EOS 달성 → Streams가 인기인 이유 중 하나. - exactly-once의 경계: 같은 Kafka 클러스터 내는 EOS 보장 가능. 다른 클러스터(MirrorMaker 등)는 source offset과 target 메시지를 한 트랜잭션으로 못 묶어 at-least-once가 한계(2.x 이후 일부 EOS 지원, 미검증). 외부 DB/HTTP는 Kafka 트랜잭션 밖 → 멱등 키·outbox 패턴 등 별도 설계.
요약 — 이 글의 결론
- 기본 = at-least-once(중복 가능). 0.11부터 exactly-once 옵션.
- idempotent producer(4.x 기본) = 단일 partition exactly-once(PID+sequence 중복 제거).
- transactions = 여러 partition 원자 쓰기 + consumer offsets과 결합.
- EOS(consume-process-produce) = 출력 메시지 + 입력 offset을 한 트랜잭션으로 원자 commit. "exactly-once는 메시지 속성이 아니라 이 원자성의 결과".
- 좀비 차단 =
transactional.id의 epoch 증가 →ProducerFencedException. isolation.level=read_committed= commit된 트랜잭션만 consumer가 읽음(EOS 필수, 단 LSO 지연 비용).- Streams EOS =
processing.guarantee=exactly_once_v2. 프레임워크가 자동 처리(트랜잭션 API 복잡도 흡수). - 발전사: at-least-once(0.11 이전) → idempotent(0.11) → transactions(0.11) → EOS v2(2.5+) → 기본 true(3.0+). 각 단계가 좁은 범위 정확성 추가.
- 경계: Kafka 클러스터 내만. 외부 DB/HTTP는 멱등 설계 필요. "Kafka가 exactly-once인가"는 범위를 정하고 물어야.
- LSO(last stable offset): read_committed consumer가 읽을 수 있는 안전 경계. 진행 중 트랜잭션이 LSO를 멈추게 함 →
transaction.timeout.ms로 상한 필수. - transaction.timeout.ms: 트랜잭션 시간 상한(기본 60초). 초과 시 강제 abort → LSO 정체·좀비 방지.
- outbox 패턴: 외부 DB까지 exactly-once가 필요할 때 Kafka 트랜잭션 대신 outbox 테이블로 DB+produce를 원자화.
- 결정 트리: 손실 허용→at-most-once, 중복 흡수 가능→at-least-once, consume-process-produce→EOS, 외부→outbox.
생각해 볼 문제
- at-most-once, at-least-once, exactly-once의 차이를 중복/손실 관점에서 설명하라.
- idempotent producer가 "exactly-once"인 정확한 범위는? 왜 "단일 partition" 한정인가?
- consume-process-produce에서 "출력과 offset을 한 트랜잭션으로"가 왜 exactly-once를 만드는가?
transactional.id가 좀비(zombie)를 차단하는 원리를 설명하라. 왜 안정적이어야 하나?read_committedconsumer가 abort된 트랜잭션을 안 보는 것이 왜 중요한가? 비용은?- Kafka만으로 외부 DB 쓰기까지 exactly-once로 만들 수 없는 이유는? 어떤 패턴으로 보완하는가?
- Kafka Streams가 EOS를 "자동"으로 달성한다는 것이 왜 강력한가?
- LSO(last stable offset)가 무엇이고, 왜 진행 중 트랜잭션이 consumer 지연을 만드는가?
- transactional.id를 재시작마다 바꾸면 어떤 일이 벌어지는가?
- 외부 DB 쓰기까지 exactly-once가 필요할 때 outbox 패턴이 어떻게 동작하는가?
- at-least-once + 애플리케이션 멱등 vs EOS — 비용 관점에서 언제 어느 쪽을 택하는가?
- 전달 보장 발전사에서 idempotent producer와 transactions가 각각 어떤 갭을 메웠는가?
- EOS 검증에서 "고의 장애 주입 후 output에 중복 없는지 확인"이 핵심인 이유는?
참고
- Design — Message Delivery Semantics / Using Transactions - 접근 2026-07-09
- ExactlyOnceMessageProcessor.java - 접근 2026-07-09
- TransactionalClientDemo.java - 접근 2026-07-09
- KIP-98(transactions), KIP-447(exactly_once_v2), KIP-833(KRaft)
- ProducerConfig.java (transaction.timeout.ms 등) - 접근 2026-07-09
'Tech Artifacts > Kafka' 카테고리의 다른 글
| Kafka - 10. kafka connect (0) | 2026.07.09 |
|---|---|
| Kafka - 09. schema registry (1) | 2026.07.09 |
| Kafka - 07. log retention (0) | 2026.07.09 |
| Kafka - 06. replication (0) | 2026.07.09 |
| Kafka - 05. consumer group (0) | 2026.07.09 |
