프로듀서와 컨슈머
프로듀서와 컨슈머
카프카에서 프로듀서(producer) 는 이벤트를 발행(쓰기) 하는 클라이언트 어플리케이션이고, 컨슈머(consumer) 는 그 이벤트를 구독(읽고 처리) 하는 클라이언트 어플리케이션이에요. 이 둘은 서로 완전히 분리되어 서로의 존재를 알지 못해요. 이것이 카프카의 높은 확장성을 만들어내는 핵심 설계 요소랍니다. 예를 들어 프로듀서는 절대 컨슈머를 기다리지 않아요.
출처: https://kafka.apache.org/intro#main-concepts-and-terminology
본문
카프카는 분산 시스템이라 서버(server) 와 클라이언트(client) 로 나뉘고, 고성능 TCP 네트워크 프로토콜로 통신해요. 서버 쪽에서 저장 계층 역할을 하는 서버를 브로커(broker) 라고 부르고요. 하나 이상의 브로커가 모여 하나의 클러스터(cluster)를 이뤄요. 브로커가 하나 죽어도 다른 서버가 그 일을 대신해 데이터 손실 없이 계속 운영되는 구조지요.
프로듀서가 이벤트를 발행할 때는 실제로 토픽의 파티션 하나에 추가돼요. 같은 키를 가진 이벤트는 같은 파티션에 쓰여져서, 그 파티션을 읽는 컨슈머는 항상 쓰인 그대로의 순서로 읽게 돼요. 그리고 파티션은 여러 개이기 때문에 여러 프로듀서가 서로 독립적으로, 동시에 다른 파티션에 쓸 수 있어요.
컨슈머는 반대로 브로커에게 "fetch(가져오기)" 요청을 보내요. 컨슈머는 로그(log) 안의 자기 오프셋(offset) 을 각 요청에 포함해서, 그 위치부터 시작하는 로그 덩어리를 받아와요. 그래서 컨슈머는 이 위치를 상당히 자유롭게 제어할 수 있고, 필요하면 되감기(rewind)해서 데이터를 다시 소비할 수도 있어요.
카프카는 컨슈머가 브로커로부터 데이터를 당겨오는(pull) 방식을 채택해요. 프로듀서가 브로커로 밀어넣고(push), 컨슈머가 브로커에서 당겨오는 구조인 거예요. 이는 대부분의 메시징 시스템이 따르는 전통적인 설계이기도 해요. 이 구조 덕분에 컨슈머는 자신의 처리 속도에 맞춰 데이터를 가져올 수 있고, 브로커 입장에서는 컨슈머가 느려도 버퍼가 넘치거나 데이터가 유실될 걱정이 적었어요.
카프카는 대용량 상태 어플리케이션을 위해 정적 멤버십(static membership) 도 지원해요. 그룹 멤버들이 영구적인 엔티티 ID(entity id)를 제공하면, 재밸런스(rebalance)가 일어나도 지연되거나 느린 멤버를 제거하지 않아서 상태를 복구하는 시간을 아낄 수 있어요. 만약 서로 다른 인스턴스에 잘못해서 같은 ID를 지정하면 브로커 쪽 펜싱(fencing) 메커니즘이 중복 클라이언트를 즉시 종료시켜요.
프로듀서는 기본적으로 at-least-once 배달을 보장하고, 재시도(retry)를 끄고 컨슈머가 배치를 처리하기 전에 오프셋을 커밋하면 at-most-once 배달을 구현할 수도 있어요. 0.11.0.0 이후부터는 멱등(idempotent) 전달 옵션도 지원해서, 네트워크 재전송이 일어나도 로그에 중복 항목이 생기지 않도록 해줘요.
더 알아보기
- 오프셋을 어디에 저장하고 어떻게 커밋하는지는 [오프셋과 커밋 관리] 문서를 봐요.
- 정확히 한 번(exactly-once) 처리를 위한 트랜잭션은 [메시지 전달 의미론] 문서에서 설명해요.
- 프로듀서 설정 항목은
producer-config, 컨슈머 설정 항목은consumer-config문서를 참고해요.