프로듀서의 내부 동작 원리와 구현
책을 읽고 정리한 내용입니다.
아직 내용 정리 중입니다.
프로듀서 디자인(3장 내용)
레코드 구성
- 토픽(필수) : 메시지를 전송할 대상 토픽 지정
- 벨류(필수) : 전송할 메시지 내용
- 파티션(선택사항) : 특정 파티션으로 지정하여 전송하기 위한 값
- 키(선택사항) : 특정 파티션에 레코드들을 정렬하기 위한 레코드의 키 값
프로듀서의 전체적인 흐름

각 레코드들은 프로듀서의 send() 메서드를 통해 시리얼라이저(serializer)와 파티셔너(partitioner)를 거쳐서 카프카로 전송됩니다.
- 프로듀서 레코드의 파티션을 지정했을 경우
- 파티셔너는 아무 동작하지 않고 지정된 파티션으로 레코드를 전달
- 프로듀서 레코드의 파티션을 지정 안했을 경우
- 키를 가지고 파티션을 선택해 레코드를 전달
- 기본적으로 라운드 로빈(round robin) 방식으로 동작
파티셔너
- 프로듀서가 토픽으로 메시지를 보낼 때 해당 토픽의 어느 파티션으로 메시지를 보내야 할지를 결정하는 데 사용하는 것
- 프로듀서의 파티션 결정하는 알고리즘
- 기본적으로 메시지의 키를 해시 처리해 파티션을 구하는 방식을 사용
- 메시지의 키 값이 동일하면 해당 메시지들은 모두 같은 파티션으로 전송
- 토픽의 파티션 늘릴 시 주의사항
- 파티션이 늘어나면 해시 알고리즘을 통해 선택되는 파티션이 달라질 수 있어 관리자의 의도와는 다른 방식으로 메시지 전송이 이뤄질 수 있으므로 되도록 파티션 수를 변경하지 않는 것을 권장
키 값을 지정하지 않았을 시 목적지 토픽 파티션에 레코드 전달 방식
- 라운드 로빈 전략(기본값)
- 라운드 로빈 알고리즘을 사용해 목적지 토픽의 파티션들로 레코드들을 각 파티션에 하나씩 순차적으로 할당하여 전송
- 배치 전송을 위한 최소 레코드 수를 충족하지 못하면 지연시간이 불필요하게 증가되는 문제가 있음
- 스티키 파티셔닝 전략
- 하나의 파티션에 레코드 수를 먼저 채워서 카프카로 빠르게 배치 전송하는 전략
- 라운드 로빈 전략에서 지연시간이 불필요하게 증가되는 비효율적인 전송을 개선하고자 2019년 출시된 아파치 카프카 2.4 버전부터 사용
- 스티키 파티셔닝 전략을 적용함으로써 기본 설정에 비해 약 30% 이상 지연시간이 감소하고 프로듀서의 CPU 사용률도 줄어드는 효과를 얻을 수 있었다 함
- 카프카로 전송하는 메시지의 순서가 그다지 중요하지 않은 경우라면 스티키 파티셔닝 전략을 적용하기를 권장
프로듀서의 배치
- 프로듀서에서 처리량을 높이기 위해 제공하는 전송 방식
- 카프카에서 토픽의 처리량을 높이기 위한 방법으로 토픽의 파티션으로 나눠 처리
- 카프카 클라이언트인 프로듀서에서는 처리량을 높이기 위해 배치 전송을 권장함
- 배치 전송을 위한 제공 옵션
- buffer.memory
- 카프카로 메시지들을 담아두는 프로듀서의 버퍼 메모리 옵션
- 기본값은 32MB로 설정되어 있으며 필요에 따라 설정값 조정 가능
- batch.size
- 배치 전송을 위해 버퍼 메모리에서 대기하는 메시지들의 최대 대기시간을 설정하는 옵션
- 밀리초(ms) 단위에 기본값은 0으로 배치 전송을 위해 기다리지 않고 즉시 전송됨
- buffer.memory
- 배치 전송 방식은 단 건의 메시지를 전송하는 것이 아니라 한 번에 대량의 메시지를 묶어서 전송하는 방법
- 불필요한 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 추천
메시지 전송 방식
사용자들의 개발 편의를 높이기 위해 중복 없이 전송할 수 있는 기능을 제공
적어도 한 번 전송
- 프로듀서가 브로커의 특정 토픽으로 메시지 A를 전송
- 브로커는 메시지 A를 기록하고, 잘 받았다는 ACK를 프로듀서에게 응답
- 브로커의 ACK를 받은 프로듀서는 다음 메시지인 메시지 B를 브로커에게 전송
- 브로커는 메시지B를 기록하고, 잘 받았다는 ACK를 프로듀서에게 전송하려고 시도하지만
네트워크 오류 또는 브로커 장애가 발생하여 결국 프로듀서는 메시지 B에 대한 ACK를 받지 못함 - 메시지 B를 전송한 후 브로커로부터 ACK를 받지 못한 프로듀서는 브로커가 메시지B를 받지 못했다고 판단해 메시지B를 재전송
최대 한 번 전송
- 프로듀서가 브로커의 특정 토픽으로 메시지 A를 전송
- 브로커는 메시지 A를 기록하고, 잘 받았다는 ACK를 프로듀서에게 응답
- 브로커의 ACK를 받은 프로듀서는 다음 메시지인 메시지 B를 브로커에게 전송
- 브로커는 메시지 B를 기록하지 못하고, 잘 받았다는 ACK를 프로듀서에게 전송하지 못함
- 프로듀서는 브로커가 메시지 B를 받았다고 가정하고, 메시지 C를 전송
중복 없는 전송
- 프로듀서가 브로커의 특정 토픽으로 메시지 A를 전송
이때 PID(ProducerID)와 메시지 번호 0을 헤더에 포함해 함께 전송 - 브로커는 메시지 A를 저장하고, PID와 메시지 번호 0을 메모리에 기록
그리고 메시지를 잘 받았다는 ACK를 프로듀서에게 응답 - 프로듀서는 다음 메시지인 메시지 B를 브로커에게 전송
PID는 동일하게 0이고, 메시지 번호는 1이 증가하여 1이 됨 - 브로커는 메시지B를 저장하고, PID와 메시지 번호 1을 메모리에 기록
그리고 메시지를 잘 받았다는 ACK를 프로듀서에게 전송하려고 하지만
네트워크 오류 또는 브로커 장애가 발생하여 프로듀서는 메시지 B에 대한 ACK를 받지 못함 - 브로커로부터 ACK를 받지 못한 프로듀서는 브로커가 메시지 B를 받지 못했다고 판단해 메시지 B를 재전송
정확히 한 번 전송
- 앞서 카프카는 멱등성 옵션을 이용해 중복 없는 전송을 할 수 있다고 설명했지만
이 중복 없는 전송 방식이 정확히 한 번 전송한다는 의미는 아님 - 카프카에서는 정확히 한 번 전송은 트랜잭션과 같은 전체적인 프로세스 처리를 의미
- 중복 없는 전송은 정확히 한 번 전송의 일부 기능이라 할 수 있음
- 전체적인 프로세스를 관리하기 위해 카프카에서는 정확히 한 번 처리를 담당하는 별도의 프로세스인 트랜잭션 API 있음
참고 서적
- 실전 카프카 개발부터 운영까지(고승범, 책만)
'dev > 기타' 카테고리의 다른 글
| port 오픈 확인 (0) | 2023.07.21 |
|---|---|
| 카프카 스트림즈와 ksqlDB 정복 - 7장 Processor API (0) | 2023.07.04 |
| [정리] 실전 카프카 개발부터 운영까지(3) (1) | 2022.10.04 |
| [정리] 실전 카프카 개발부터 운영까지(1) (0) | 2022.07.19 |
| 특정 IP의 특정 Port Open 여부 확인 (0) | 2022.06.21 |