
이전 글에서는 Kafka Producer의 동작 원리와 비동기 전송 구조를 살펴봤다.
이번 글에서는 Producer가 데이터를 어떻게 안전하게 전송하고, 메시지 손실이나 중복을 방지하는지를 중심으로 정리한다.
Kafka Producer는 메시지를 한 건씩 전송하지 않는다.
여러 개의 메시지를 모아 배치(batch) 로 묶고, 이를 전송하기 전까지 임시로 저장하는 공간이 RecordAccumulator다.
ProducerRecord → RecordBatch → RecordAccumulator → Sender
| 설정 | 의미 |
|---|---|
batch.size | 배치 최대 크기 (byte 단위) |
linger.ms | 배치 대기 시간 |
buffer.memory | Accumulator 총 버퍼 용량 |
| 구성 요소 | 설명 |
|---|---|
| ProducerRecord | 프로듀서가 생성하는 개별 메시지 단위. Topic, Key, Value... 포함 |
| RecordBatch | 동일한 Topic-Partition으로 향하는 ProducerRecord 묶음 |
| RecordAccumulator | 배치를 관리하는 버퍼. 배치가 가득 차거나 대기 시간이 지나면 Sender가 전송 |

Producer는 메시지를 보낸 뒤 브로커의 응답(acknowledgment)을 기다린다.
이때 어디까지 응답을 받아야 전송이 성공했다고 판단할지를 지정하는 설정이 acks다.
| 값 | 설명 |
|---|---|
acks=0 | 브로커의 응답을 기다리지 않음 (가장 빠르지만 데이터 손실 가능성 있음) |
acks=1 | 리더 파티션이 메시지를 수신하면 성공으로 간주 |
acks=all | 모든 복제 파티션(ISR)이 메시지를 저장해야 성공으로 간주 (가장 안전함) |
acks=0은 최소 지연을 원할 때 사용하지만, 장애 시 데이터 유실이 발생한다. acks=1은 리더 파티션을 가진 브로커에 장애가 생기면 데이터를 유실 의 가능성이있다. acks=all은 리더 + 팔로워 모두 저장 완료 후 응답하므로 가장 안전하다.운영 환경에서는
acks=all을 사용하고, ISR 관리로 복제 상태를 모니터링하는 것이 일반적이다.
Kafka Producer는 데이터를 전송할 때 네트워크 지연이나 브로커 부하로 인해 전송이 실패할 수 있다.
이때 내부적으로 재전송(retry) 메커니즘이 작동하며, 이를 제어하는 다양한 파라미터가 존재한다.
| 설정 | 역할 | 설명 |
|---|---|---|
max.block.ms | Accumulator 대기 한도 | 버퍼가 가득 찼을 때 send()가 block되는 최대 시간 |
request.timeout.ms | 브로커 응답 대기 시간 | ack가 오지 않으면 TimeoutException 또는 retry 발생 |
retry.backoff.ms | 재시도 간격 | 전송 실패 후 다음 시도까지의 대기 시간 |
delivery.timeout.ms | 전체 전송 허용 시간 | 배치가 전송 완료될 수 있는 총 시간 |
retries | 재전송 횟수 | 지정 횟수 내에서 재시도 수행 (보통 시간 기반 조정 권장) |
이 설정들은 함께 작동하며,
보통 다음 관계가 유지되어야 안정적으로 동작한다.
delivery.timeout.ms >= linger.ms + request.timeout.ms
배치를 모으는 시간과 브로커 응답 시간을 합친 것보다 전체 전송 제한 시간이 커야 전송 중 불필요한 Timeout이 발생하지 않는다.
max.in.flight.requests.per.connection은
Producer가 동시에 보낼 수 있는 요청(배치)의 개수를 의미한다.
기본값은 5이며 이 값이 클수록 병렬 처리가 가능해 처리량은 늘어나지만
전송 중 실패나 재시도가 발생할 경우 메시지 순서가 뒤바뀔 가능성이 생긴다.
Kafka는 기본적으로 같은 파티션 내에서는 순서를 보장하지만 비동기 전송과 재시도가 동시에 일어날 경우
메시지가 송신된 순서와 다르게 도착할 수 있다.
A와 B를 순서대로 전송했을 때
A가 전송 실패 후 재시도되는 동안 B가 먼저 성공하면
브로커에는 B → A 순서로 저장될 수 있다.
이처럼 재전송과 병렬 전송이 결합될 때 발생하는 순서 역전(out-of-order) 문제를 해결하기 위해 Kafka는 이후 Idempotent Producer(멱등 프로듀서) 개념을 도입하게 된다.
Kafka의 전송 보장은 메시지가 손실되거나 중복될 가능성을 기준으로 세 가지로 구분된다.
| 전송 보장 수준 | 설명 |
|---|---|
| At Most Once (최대 한 번) | 실패 시 재전송하지 않음 → 손실 가능성 존재, 중복 없음 |
| At Least Once (적어도 한 번) | 실패 시 재전송 → 손실 없음, 중복 가능 |
| Exactly Once (중복 없이 정확히 한 번) | 손실·중복 모두 방지 (Idempotent Producer 필요) |
acks=0
retries=0
acks=all
retries=Integer.MAX_VALUE

enable.idempotence=true
Kafka의 멱등성(Idempotence)은
Producer와 Broker 간의 메시지 재전송(retry) 시 중복 저장을 방지하는 메커니즘이다.
즉, 전송 중 실패하여 재시도되는 동일한 메시지를 한 번만 저장하도록 보장한다.
Kafka는 Producer에 고유한 PID(Producer ID) 를 부여하고,
각 메시지에 Sequence Number를 함께 전송한다.
enable.idempotence=true를 설정하면 Kafka는 자동으로 다음 구성을 적용한다.
acks=all
retries=Integer.MAX_VALUE
max.in.flight.requests.per.connection<=5
멱등성은 Producer 내부 전송 단위에서만 중복 제거를 보장한다.
다음과 같은 상황에서는 여전히 중복 전송이 발생할 수 있다.
동일 메시지를 send()로 두 번 호출한 경우
→ 명시적으로 다른 요청으로 간주되며, 멱등성 대상이 아님
Producer 재기동 후 전송
→ 새로운 PID가 부여되어 이전 Producer의 메시지를 구분하지 못함
Consumer → Process → Producer 구조에서 Consumer가 offset 커밋 전에 메시지를 전송한 경우
→ Consumer가 재시작 시 이전 offset부터 다시 읽어 동일 메시지를 다시 전송할 수 있음
이러한 애플리케이션 단의 중복까지 완전히 제거하려면 Transaction 기반 처리가 필요하다.
https://github.com/develkkm/kafka-from-0/tree/kafka-core/producers