-
Acks = 0 에서의 Producer

- producer는 Leader broker가 메시지를 받았는지에 대한 Ack 메시지를 받지 않고 다음 메시지를 전송
- 전송 실패/성공 여부에 대해 받지 않기 때문에 기록되지 않더라도 재처리가 없음
- 메시지 손실은 있지만 빠르게 전송 가능
-
Acks = 1에서의 Producer

- producer는 Leader broker가 메시지 A를 정상적으로 받았는지 Ack 메시지를 받은 후 다음 메시지를 전송
- 메시지가 모든 follwer broker에 저장되었는지 확인하지는 않고 전송(Leader broker만 확인)
- 만약 Leader broker에서 Follwer broker로 메시지 복제 중에 다운될 경우 Follwer broker가 Leader broker가 되면서 복제되지 못한 메시지는 소실될 수 있음
-
Acks = all에서의 Producer

- producer는 Leader broker가 메시지를 받은 뒤 Follwer broker로 복제를 모두 마친 뒤에 Acks 메시지를 받은 후 다음 메시지를 처리
- 즉, 메시지가 Follwer broker까지 안전하게 복사가 되었는지 확인 후 다음 메시지 전송
- 메시지가 소실되는 경우는 작지만 Follwer broker까지의 저장을 기다리므로 오래 걸릴 수 있음
min.insync.replicas
- 최소 broker개수를 지정
- 2를 지정하고 Follwer broker들이 모두 다운된 경우 현재 사용가능한 브로커는 1대인데, 이때 설정값보다 작으므로 에외 발생
-
producer의 Sync와 Callback Async에서의 acks와 retry
- callback 기반의 async에서도 동일하게 acks설정에 기반하여 retry동작
- callback 기반의 async에서는 retry에 따라 producer의 기존 메시지 전송 순서와 기록되는 메시지 순서는 달라질 수 있음
- sync방식에서 acks = 0일 경우 전송 후 ack/error를 기다리지 않음(fire and forget)
-
Producer의 메시지 배치 전송의 이해

- **
send()**메서드를 통해 ProducerRecord를 입력
- 하지만, 바로 전송되지 않고 내부 메모리에서 단일 메시지를 토픽 파티션에 따라 Record Batch 단위로 묶은 뒤 전송
- 메시지들은 Producer Client의 내부 메모리에 여러 개의 Batch들로
buffer.memory 설정 사이즈만큼 보관될 수 있음
- 또한, 여러 개의 Batch들로 한꺼번에 전송될 수 있음
-
Record Accumulator

-
Record Accumulator는 Partitioner에 의해서 메시지 배치가 전송이 될 토픽과 Partition에 따라 저장되는 KafkaProducer 메모리 영역
-
Sender Thread는 Record Accumulator에 누적된 메시지 배치를 꺼내서 브로커로 전송
-
KafkaProducer의 Main Thread는 send()메서드를 호출하고 Record Accumulator에 데이터 저장하고 Sender Thread는 별개로 데이터를 브로커로 전송
-
linger.ms

- Sender Thread로 메시지를 보내기 전 대기 시간
- 만약 Batch가 다 차지 않더라도 보낼 때 최대 대기 시간을 지정할 수 있음
- 일정 시간 대기를 통해 Record Batch에 메시지를 보다 많이 채울 수 있도록
- Producer, Broker간의 전송이 빠른 경우 0으로 해도 무방(전송 응답이 빠른데 굳이 기다릴 필요 없음)
- 보통 20ms 이하로 설정 권장
-
Sender Thread

- 기본적으로 전송할 준비가 되어 있으면 Record Accumulator를 읽어서 전송
- 전송할 때 1개 또는 여러개의 Batch를 가져갈 수 있음
- 또한 특정 Batch가 다 채워지지 않아도 전송 가능
max.inflight.requests.per.connection을 통해 각 파티션별로 전송할 때 최대 Batch 개수 설정
-
Producer의 동기와 비동기에서의 Batch
- 기본적으로
send()메서드는 비동기 전송하며 Batch 단위 전송
- Callback 기반의 비동기 전송은 RecordMetadata를 Client가 받을 수 있는 방식 제공
- Callback 기반의 비동기 전송은 여러 개의 메시지가 Batch로 만들어짐
- 동기 전송인
get()에서는 배치에 메시지가 1개(전송 성공에 대해 응답을 받을 때까지 Batch를 채우지 않기 때문)
-
Producer의 메시지 전송/재전송 시간 파라미터 이해

-
max.block.ms
send()호출하여 Record Accumulator에 append를 시도하려고 할 때 Record Accumulator가 가득찬 경우
- Record Accumulator에 append하기 위해 기다리는 시간
- 시간을 초과한 경우 예외를 던짐
-
request.timeout.ms
- Sender Thread가 브로커로 전송할 때 브로커가 에러 또는 응답이 없는 경우 기다리는 시간
- 시간 초과할 경우 예외를 던짐
-
retry.backoff.ms
- Sender Thread가 응답이 없어
request.timeout.ms만큼 기다리고 재전송 전 기다리는 시간
-
delivery.timeout.ms
- Sender Thread가 전송 실패시 retry를 수행하는 최대 시간
- 즉, Producer 메시지 전송에 허용된 최대 시간
delivery.timeout.ms >= linger.ms + request.timeout.ms 또는 delivery.timeout.ms >= linger.ms + retry.backoff.ms + request.timeout.ms 지켜져야함
-
retries(재전송 횟수)

- retries는 매우 큰 값을 기본값으로 가짐(int 횟수)
- 하지만,
delivery.timeout.ms를 초과하게 되면 전송 실패 처리를 하기 때문에 retries 설정된 만큼 재전송하는 경우는 없음
-
max.in.flight.requests.per.connection 이해

-
브로커 서버의 응답 없이 Producer의 sender Thread가 한번에 보낼 수 있는 메시지 배치의 개수
-
default = 5, Kafka Producer의 메시지 전송 단위는 Batch
-
비동기 전송 시 브로커의 응답없이 한꺼번에 보낼 수 있는 Batch의 개수는 max.in.flight.requests.per.connection에 따름
-
배치 전송 시 발생하는 상황

- 위 상황에서 B0, B1 배치가 전송되었을 때 B1은 저장되었는데, B0는 저장 실패
- Producer는 B0를 재전송하여 성공적으로 기록
- 이런 경우 기대한 저장 순서와 달라질 수 있다는 점
-
최대 한번 전송, 적어도 한번 전송, 정확히 한번 전송
-
최대 한번 전송(ack = 0)

- Producer는 브로커로부터 Ack 또는 에러 메세지에 상관하지 않고 다음 메세지 처리
- 메세지가 소실될 수는 있지만 중복 전송은 일어나지 않음
-
적어도 한번 전송(ack = 1, all)

- Producer는 브로커로 부터 Ack를 받은 다음에 다음 메세지 전송
- 메시지 소실은 없지만 중복 전송을 할 수 있음
-
중복 없이 전송(idempotence)

- Producer는 브로커로 부터 Ack를 받은 다음에 다음 메세지를 전송하되, Producer ID와 메시지 Seq를 Header에 넣어 전송
- 메시지 Seq는 메시지의 고유 Seq번호, 0…순차적 증가, Producer ID는 매번 새롭게 작성
- 브로커에서 메시지 Seq가 중복되는 경우 → 메세지 로그에 기록하지 않고 Ack만 전송
- 브로커는 Producer가 보낸 메세지의 Seq가 브로커가 가지고 있는 메세지의 Seq보다 1만큼 큰 경우에만 브로커에 저장
- Producer의 idempotence 설정
- idempotence 기반에서 메시지 전송 순서 유지
-
idempotence를 위한 Producer 설정
-
Custom 파티셔너를 통해 특정 Partition 설정하기