Infra/Kafka

Apache Kafka (4) - Producer

코드파고 2024. 11. 20. 20:26

Apache Kafka Series - Learn Apache Kafka for Beginners v3를 수강하며 기록한 내용입니다.

ACKS

정상적으로 메시지를 수신했는지에 대한 플래그

ACK = 1

  • 3.0 버전 미만은 default
  • "리더"로부터 ACK를 수신하면 제대로 Write가 수행되었다고 판단한다
    • 만일 리더가 다운된다면, replica들이 제대로 메시지를 복제하지 않았을 가능성이 있다.
  • ACK가 수신되지 않았다면 producer는 재시도

ACK = all(-1)

  • 3.0 버전 이후부터 default
  • 모든 ISR(in-sync Replica)에서 메시지가 수신됨

min.insync.replicas

  • ACKS=all로 메시지를 보낼 때 최소 동기화된 파티션 복제본(리더 포함)의 수
  • 이는 브로커에 기입

min.insync.replicas에 따른 브로커 다운 허용 규칙

  1. min.insync.replicas = 1
    • 최소 1개 복제본만 동기화 상태라면 메시지를 받음.
    • 최대 2개 브로커가 다운되어도 메시지를 처리 가능 -> 남아있는 리더 하나만 동기화되어 있어도 메시지 전송 성공.
  2. min.insync.replicas = 2
    • 최소 2개 복제본이 동기화 상태여야 메시지를 받음.
    • 남아있는 2개의 복제본(리더 + 팔로워)이 동기화 상태여야 함.
    • 허용 가능 브로커 다운 수: 최대 1개 브로커가 다운 가능.
  3. min.insync.replicas = 3
    • 모든 복제본(3개)이 동기화 상태여야 메시지를 받음.
    • 허용 가능 브로커 다운 수: 0개 (1개라도 다운되면 메시지 전송 불가

보통 acks=all + min.insync.replicas=2 정도를 선호한다.
NOT_ENOUGH_REPLICAS를 일으킬 수 있으므로 설정에 주의하자

Producer Retries

  • reties 설정
    • <=2.0 버전 : default : 0
    • >=2.1 버전 : default : 2147483647 (Integer.MAX_VALUE)
  • delivey.timeout.ms = 12000 = 2분
    • 해당 시간 안에 ACK 를 수신하지 않으면 FAIL
  • idempotent producer를 사용하지 않으면(구버전 카프카가 그러하다), 순서가 바뀌게 된다.
  • max.in.flight.requests.per.connection
    • 브로커에 동시에 보내는 요청 최대 수
    • default : 5
    • 순서 보장을 위해서라면 1로 세팅(하지만 처리량이 저하)
  • kafka 1.0.0 이상부터는 Idempotent Producer로 개선됨

Idempotent Producer

중복 데이터를 방지하여 안정적이고, 안전한 파이프라인을 보장한다.

  • 정상 플로우
    • Producer Produce -> Kafka Commit -> Kafka send ACK -> Producer receives ACK
  • 중복 플로우
    • Producer Produce -> Kafka Commit -> Kafka does not send ACK -> Producer Retry -> Commit Duplicate

중복 플로우 내 마지막 비정상 단계(Commit Duplicate)를 방지한다.

설정방법

3.0 미만 카프카에서는 아래와 같이 설정해주고,

  • retries = Integer.MAX_VALUE
  • max.in.flight.request = 1
  • max.in.flight.request = 5

3.0 이상 카프카에서는
producerProps.put("enable.idempotence", true);
로 설정하자

정리) 3.0 이상 카프카를 쓰는 것을 권장한다.
acks=all
min.insync.replicas=2
enable.idempotencce=true
retries=MAX_INT
deliver.timeout.ms=12000
max.in.flight.request=5

코드레벨에서 Producer 설정하기

properties.setProperty(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, "true");  
properties.setProperty(ProducerConfig.ACKS_CONFIG, "all");  
properties.setProperty(ProducerConfig.RETRIES_CONFIG, Integer.toBinaryString(Integer.MAX_VALUE));

Compression

장점

  • 1/4까지 압축 가능하여 지연을 최소화
  • 배치 사이즈가 크다면 처리량을 높여 효율적이다
  • 단점*
  • CPU Cycle 소비

압축 타입
none, gzip,lz4, snappy, zstd

브로커 레벨 혹은 토픽 레벨에서 압축이 이루어질 수 있음

compression.type

  • producer (default)
    • 브로커가 수신한 메시지 그대로 토픽의 로그에 적재
    • consumer 쪽에서 압축 해제
  • none
    • 브로커가 다 압축 해제
  • lz4,, etc
    • 프로듀서 압축 타입과 일치 시 그대로 저장
    • 타입이 다르면 브로커가 압축 해제하고 명시된 압축 알고리즘으로 재압축

linger.ms & batch.size

기본으로 카프카 프로듀서는 레코드를 즉시 보낸다.

  • max.in.flight.request.per.connection=5 설정을 통하여 동시에 보낼 배치 사이즈를 설정할 수 있다.
  • 만일 위 설정을 초과(ex. 5개 배치 전송중) 한다면, 들어온 초과 메시지들을 다음에 전송할 배치로 묶고 있을 것임
    배치 설정
  • linger.ms(default:0)
    • 배치를 보낼 때 까지 얼마나 기다릴지에 대한 설정. 만약 5ms 라면 5ms동안 들어오는 메시지를 배칭할 것임
    • properties.setProperty(ProducerConfig.LINGER_MS_CONFIG, "20");
  • batch.size
    • 배치에 담을 수 있는 최대 메시지 수
    • properties.setProperty(ProducerConfig.BATCH_SIZE_CONFIG, "32*1024");

Default Partitioner

  • 키가 있을 때
    • murmur 알고리즘을 사용하여 해싱
  • 키가 없을 때
    • Round Robin : 메시지를 하나씩 균등하게 전송
    • Sticky Partitioner : 메시지를 묶어 한 번 선택한 파티션에 묶어서 일정 시간 동안 전송
    • 파티션이 증가할 수록 Sticky Partitioner가 낮은 지연률을 보인다.

max.block.ms & buffer.memory

  • 프로듀서 생산속도가 브로커 수용 속도보다 빠르다면, 레코드는 메모리에 쌓이게 된다.
  • buffer.memory = 33554432(32MB) 로 버퍼 사이즈 설정 가능
    • 이보다 크다면, block된다.
    • max.block.ms 의 값보다 지연 시간이 길어지면, exception이 발생한다.
  • 예외가 발생하는 경우를 보자면 다음과 같다
    • 프로듀서가 버퍼를 다 채운 경우
    • 브로커가 데이터를 받지 않는 경우
    • max.block.ms 시간을 초과한 경우