Kafka - Producer 2

develkkm·2025년 11월 8일

이전 글에서는 Kafka Producer의 동작 원리와 비동기 전송 구조를 살펴봤다.
이번 글에서는 Producer가 데이터를 어떻게 안전하게 전송하고, 메시지 손실이나 중복을 방지하는지를 중심으로 정리한다.


RecordAccumulator

Kafka Producer는 메시지를 한 건씩 전송하지 않는다.
여러 개의 메시지를 모아 배치(batch) 로 묶고, 이를 전송하기 전까지 임시로 저장하는 공간이 RecordAccumulator다.

ProducerRecord → RecordBatch → RecordAccumulator → Sender

주요 설정값

설정의미
batch.size배치 최대 크기 (byte 단위)
linger.ms배치 대기 시간
buffer.memoryAccumulator 총 버퍼 용량

구조 요약

구성 요소설명
ProducerRecord프로듀서가 생성하는 개별 메시지 단위. Topic, Key, Value... 포함
RecordBatch동일한 Topic-Partition으로 향하는 ProducerRecord 묶음
RecordAccumulator배치를 관리하는 버퍼. 배치가 가득 차거나 대기 시간이 지나면 Sender가 전송

acks

Producer는 메시지를 보낸 뒤 브로커의 응답(acknowledgment)을 기다린다.
이때 어디까지 응답을 받아야 전송이 성공했다고 판단할지를 지정하는 설정이 acks다.

설명
acks=0브로커의 응답을 기다리지 않음 (가장 빠르지만 데이터 손실 가능성 있음)
acks=1리더 파티션이 메시지를 수신하면 성공으로 간주
acks=all모든 복제 파티션(ISR)이 메시지를 저장해야 성공으로 간주 (가장 안전함)
  • acks=0최소 지연을 원할 때 사용하지만, 장애 시 데이터 유실이 발생한다.
  • acks=1은 리더 파티션을 가진 브로커에 장애가 생기면 데이터를 유실 의 가능성이있다.
  • acks=all리더 + 팔로워 모두 저장 완료 후 응답하므로 가장 안전하다.

운영 환경에서는 acks=all을 사용하고, ISR 관리로 복제 상태를 모니터링하는 것이 일반적이다.


메시지 전송 / 재전송

Kafka Producer는 데이터를 전송할 때 네트워크 지연이나 브로커 부하로 인해 전송이 실패할 수 있다.
이때 내부적으로 재전송(retry) 메커니즘이 작동하며, 이를 제어하는 다양한 파라미터가 존재한다.

재전송 관련 주요 설정

설정역할설명
max.block.msAccumulator 대기 한도버퍼가 가득 찼을 때 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

max.in.flight.requests.per.connection
Producer가 동시에 보낼 수 있는 요청(배치)의 개수를 의미한다.

기본값은 5이며 이 값이 클수록 병렬 처리가 가능해 처리량은 늘어나지만
전송 중 실패나 재시도가 발생할 경우 메시지 순서가 뒤바뀔 가능성이 생긴다.

순서 고찰

Kafka는 기본적으로 같은 파티션 내에서는 순서를 보장하지만 비동기 전송과 재시도가 동시에 일어날 경우
메시지가 송신된 순서와 다르게 도착할 수 있다.

A와 B를 순서대로 전송했을 때
A가 전송 실패 후 재시도되는 동안 B가 먼저 성공하면
브로커에는 B → A 순서로 저장될 수 있다.

이처럼 재전송과 병렬 전송이 결합될 때 발생하는 순서 역전(out-of-order) 문제를 해결하기 위해 Kafka는 이후 Idempotent Producer(멱등 프로듀서) 개념을 도입하게 된다.


전송 보장 (Delivery Guarantee)

Kafka의 전송 보장은 메시지가 손실되거나 중복될 가능성을 기준으로 세 가지로 구분된다.

전송 보장 수준설명
At Most Once (최대 한 번)실패 시 재전송하지 않음 → 손실 가능성 존재, 중복 없음
At Least Once (적어도 한 번)실패 시 재전송 → 손실 없음, 중복 가능
Exactly Once (중복 없이 정확히 한 번)손실·중복 모두 방지 (Idempotent Producer 필요)

At Most Once

acks=0
retries=0
  • 빠르지만 메시지 손실 위험이 큼
  • 일부 데이터 유실이 허용되는 환경에서만 사용 가능

At Least Once

acks=all
retries=Integer.MAX_VALUE
  • 재전송을 통해 손실은 방지하지만,
    동일 메시지가 중복 저장될 수 있음
  • 대부분의 애플리케이션이 사용하는 기본 형태

Exactly Once — Idempotent Producer

enable.idempotence=true

Kafka의 멱등성(Idempotence)은
Producer와 Broker 간의 메시지 재전송(retry) 시 중복 저장을 방지하는 메커니즘이다.

즉, 전송 중 실패하여 재시도되는 동일한 메시지를 한 번만 저장하도록 보장한다.

동작 방식

Kafka는 Producer에 고유한 PID(Producer ID) 를 부여하고,
각 메시지에 Sequence Number를 함께 전송한다.

  • 브로커는 각 파티션별 마지막 Sequence Number를 기억한다.
  • 이미 처리된 번호의 메시지가 다시 도착하면 중복으로 판단하고 무시한다.
  • 따라서 전송 중 재시도에 의한 중복만 제거된다.

멱등성을 위한 자동 설정

enable.idempotence=true를 설정하면 Kafka는 자동으로 다음 구성을 적용한다.

acks=all
retries=Integer.MAX_VALUE
max.in.flight.requests.per.connection<=5
  • 모든 복제본이 ack를 보낼 때까지 대기
  • 재전송 무제한 허용
  • 순서 보장을 위해 동시 요청 제한

Idempotence의 한계

멱등성은 Producer 내부 전송 단위에서만 중복 제거를 보장한다.
다음과 같은 상황에서는 여전히 중복 전송이 발생할 수 있다.

  • 동일 메시지를 send()로 두 번 호출한 경우
    → 명시적으로 다른 요청으로 간주되며, 멱등성 대상이 아님

  • Producer 재기동 후 전송
    → 새로운 PID가 부여되어 이전 Producer의 메시지를 구분하지 못함

  • Consumer → Process → Producer 구조에서 Consumer가 offset 커밋 전에 메시지를 전송한 경우
    → Consumer가 재시작 시 이전 offset부터 다시 읽어 동일 메시지를 다시 전송할 수 있음

이러한 애플리케이션 단의 중복까지 완전히 제거하려면 Transaction 기반 처리가 필요하다.


실습

https://github.com/develkkm/kafka-from-0/tree/kafka-core/producers

profile
알던것을 더 확실하게

0개의 댓글