Notepad
article thumbnail

프로듀서의 내부 동작 원리와 구현

책을 읽고 정리한 내용입니다.
아직 내용 정리 중입니다.

프로듀서 디자인(3장 내용)

레코드 구성

  • 토픽(필수) : 메시지를 전송할 대상 토픽 지정
  • 벨류(필수) : 전송할 메시지 내용
  • 파티션(선택사항) : 특정 파티션으로 지정하여 전송하기 위한 값
  • 키(선택사항) : 특정 파티션에 레코드들을 정렬하기 위한 레코드의 키 값

 

프로듀서의 전체적인 흐름

프로듀서 디자인 개요(출처: https://dzone.com/articles/take-a-deep-dive-into-kafka-producer-api)

각 레코드들은 프로듀서의 send() 메서드를 통해 시리얼라이저(serializer)와 파티셔너(partitioner)를 거쳐서 카프카로 전송됩니다.

  • 프로듀서 레코드의 파티션을 지정했을 경우
    • 파티셔너는 아무 동작하지 않고 지정된 파티션으로 레코드를 전달
  • 프로듀서 레코드의 파티션을 지정 안했을 경우
    • 키를 가지고 파티션을 선택해 레코드를 전달
    • 기본적으로 라운드 로빈(round robin) 방식으로 동작

 

파티셔너

  • 프로듀서가 토픽으로 메시지를 보낼 때 해당 토픽의 어느 파티션으로 메시지를 보내야 할지를 결정하는 데 사용하는 것
  • 프로듀서의 파티션 결정하는 알고리즘
    • 기본적으로 메시지의 키를 해시 처리해 파티션을 구하는 방식을 사용
    • 메시지의 키 값이 동일하면 해당 메시지들은 모두 같은 파티션으로 전송
  • 토픽의 파티션 늘릴 시 주의사항
    • 파티션이 늘어나면 해시 알고리즘을 통해 선택되는 파티션이 달라질 수 있어 관리자의 의도와는 다른 방식으로 메시지 전송이 이뤄질 수 있으므로 되도록 파티션 수를 변경하지 않는 것을 권장

키 값을 지정하지 않았을 시 목적지 토픽 파티션에 레코드 전달 방식

  • 라운드 로빈 전략(기본값)
    • 라운드 로빈 알고리즘을 사용해 목적지 토픽의 파티션들로 레코드들을 각 파티션에 하나씩 순차적으로 할당하여 전송
    • 배치 전송을 위한 최소 레코드 수를 충족하지 못하면 지연시간이 불필요하게 증가되는 문제가 있음
  • 스티키 파티셔닝 전략
    • 하나의 파티션에 레코드 수를 먼저 채워서 카프카로 빠르게 배치 전송하는 전략
    • 라운드 로빈 전략에서 지연시간이 불필요하게 증가되는 비효율적인 전송을 개선하고자 2019년 출시된 아파치 카프카 2.4 버전부터 사용
    • 스티키 파티셔닝 전략을 적용함으로써 기본 설정에 비해 약 30% 이상 지연시간이 감소하고 프로듀서의 CPU 사용률도 줄어드는 효과를 얻을 수 있었다 함
    • 카프카로 전송하는 메시지의 순서가 그다지 중요하지 않은 경우라면 스티키 파티셔닝 전략을 적용하기를 권장

 

프로듀서의 배치

  • 프로듀서에서 처리량을 높이기 위해 제공하는 전송 방식
    • 카프카에서 토픽의 처리량을 높이기 위한 방법으로 토픽의 파티션으로 나눠 처리
    • 카프카 클라이언트인 프로듀서에서는 처리량을 높이기 위해 배치 전송을 권장함
  • 배치 전송을 위한 제공 옵션
    • buffer.memory
      • 카프카로 메시지들을 담아두는 프로듀서의 버퍼 메모리 옵션
      • 기본값은 32MB로 설정되어 있으며 필요에 따라 설정값 조정 가능
    • batch.size
      • 배치 전송을 위해 버퍼 메모리에서 대기하는 메시지들의 최대 대기시간을 설정하는 옵션
      • 밀리초(ms) 단위에 기본값은 0으로 배치 전송을 위해 기다리지 않고 즉시 전송됨
  • 배치 전송 방식은 단 건의 메시지를 전송하는 것이 아니라 한 번에 대량의 메시지를 묶어서 전송하는 방법
    • 불필요한 I/O를 줄일 수 있어 효율적(카프카 요청 수를 줄여주는 효과)
    • 1000개의 메시지를 카프카로 전송한다면 1000번의 요청과 응답이 발생하지만, 
      프로듀서가 100개의 메시지를 배치로 처리하면 10번으로 요청과 응답만 발생
  • 카프카를 사용하는 목적에 따라 처리량을 높일지, 아니면 지연 전송을 해야 할지 선택해야 함
    • 대량의 메시지를 처리할 때 처리량을 높여야 하는 경우에는 배치 전송을 위한 설정 적용
      • batch.size와 linger.ms 값을 크게 설정
      • buffer.memory 크기는 반드시 batch.size 보다 크게 설정
        • 토픽이 파티션 3개에 batch.size 가 16KB 라면 buffer.memory의 최소 크기는 16KB * 3 이 되어야 함
        • 재시도까지 고려하면 48KB 보다 더 큰 값으로 설정해야 함
    • 단지 지연 없는 전송이 목표라면 배치 전송 관련 설정을 제거해야 함
      • batch.size 와 linger.ms의 값을 작게 설정
  • 압축 기능을 같이 사용하면 메시지들을 더욱 효율적으로 카프카로 전송 가능
    • 높은 압축률을 선호한다면 gzip, zstd 추천
    • 낮은 지연시간을 선호한다면 lz4, snappy 추천

 

메시지 전송 방식

사용자들의 개발 편의를 높이기 위해 중복 없이 전송할 수 있는 기능을 제공

 

적어도 한 번 전송

  1. 프로듀서가 브로커의 특정 토픽으로 메시지 A를 전송
  2. 브로커는 메시지 A를 기록하고, 잘 받았다는 ACK를 프로듀서에게 응답
  3. 브로커의 ACK를 받은 프로듀서는 다음 메시지인 메시지 B를 브로커에게 전송
  4. 브로커는 메시지B를 기록하고, 잘 받았다는 ACK를 프로듀서에게 전송하려고 시도하지만
    네트워크 오류 또는 브로커 장애가 발생하여 결국 프로듀서는 메시지 B에 대한 ACK를 받지 못함
  5. 메시지 B를 전송한 후 브로커로부터 ACK를 받지 못한 프로듀서는 브로커가 메시지B를 받지 못했다고 판단해 메시지B를 재전송

 

최대 한 번 전송

  1. 프로듀서가 브로커의 특정 토픽으로 메시지 A를 전송
  2. 브로커는 메시지 A를 기록하고, 잘 받았다는 ACK를 프로듀서에게 응답
  3. 브로커의 ACK를 받은 프로듀서는 다음 메시지인 메시지 B를 브로커에게 전송
  4. 브로커는 메시지 B를 기록하지 못하고, 잘 받았다는 ACK를 프로듀서에게 전송하지 못함
  5. 프로듀서는 브로커가 메시지 B를 받았다고 가정하고, 메시지 C를 전송

 

중복 없는 전송

  1. 프로듀서가 브로커의 특정 토픽으로 메시지 A를 전송
    이때 PID(ProducerID)와 메시지 번호 0을 헤더에 포함해 함께 전송
  2. 브로커는 메시지 A를 저장하고, PID와 메시지 번호 0을 메모리에 기록
    그리고 메시지를 잘 받았다는 ACK를 프로듀서에게 응답
  3. 프로듀서는 다음 메시지인 메시지 B를 브로커에게 전송
    PID는 동일하게 0이고, 메시지 번호는 1이 증가하여 1이 됨
  4. 브로커는 메시지B를 저장하고, PID와 메시지 번호 1을 메모리에 기록
    그리고 메시지를 잘 받았다는 ACK를 프로듀서에게 전송하려고 하지만
    네트워크 오류 또는 브로커 장애가 발생하여 프로듀서는 메시지 B에 대한 ACK를 받지 못함
  5. 브로커로부터 ACK를 받지 못한 프로듀서는 브로커가 메시지 B를 받지 못했다고 판단해 메시지 B를 재전송

 

정확히 한 번 전송

  • 앞서 카프카는 멱등성 옵션을 이용해 중복 없는 전송을 할 수 있다고 설명했지만
    이 중복 없는 전송 방식이 정확히 한 번 전송한다는 의미는 아님
  • 카프카에서는 정확히 한 번 전송은 트랜잭션과 같은 전체적인 프로세스 처리를 의미
    • 중복 없는 전송은 정확히 한 번 전송의 일부 기능이라 할 수 있음
  • 전체적인 프로세스를 관리하기 위해 카프카에서는 정확히 한 번 처리를 담당하는 별도의 프로세스인 트랜잭션 API 있음

 

 

참고 서적

  • 실전 카프카 개발부터 운영까지(고승범, 책만)
profile

Notepad

@Apio

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!