3. 프로듀서(Producer)의 모든 것: 메시지 전송 방식과 내부 동작 원리

프로듀서의 역할과 중요성

카프카 프로듀서(Producer)는 데이터를 생성하여 카프카 클러스터의 토픽(Topic)으로 전송하는 클라이언트 애플리케이션입니다. 단순히 데이터를 보내는 역할을 넘어, '어떻게' 보내느냐에 따라 전체 데이터 파이프라인의 성능, 안정성, 데이터 무결성이 결정됩니다. 프로듀서의 내부 동작과 핵심 설정을 이해하는 것은 대용량 트래픽 환경에서 발생할 수 있는 다양한 문제를 예방하고 해결하는 데 필수적입니다.

프로듀서의 내부 동작 원리

프로듀서가 send() 메서드를 호출하면, 메시지는 즉시 네트워크를 통해 전송되는 것이 아니라 여러 단계를 거치는 정교한 비동기 프로세스를 따릅니다.

graph TD A[애플리케이션] -->|1. ProducerRecord 생성| B(Serializer); B -->|2. Key/Value 직렬화| C(Partitioner); C -->|3. 파티션 결정| D(Record Accumulator); D -->|4. 파티션별 배치 구성| E[Sender Thread]; E -->|5. 배치 전송| F((Kafka Broker));
  1. ProducerRecord 생성: 전송할 토픽, 파티션(선택), 키(선택), 값(메시지 본문)을 담은 ProducerRecord 객체를 생성합니다.
  2. 직렬화(Serialization): 키와 값 객체를 네트워크로 전송 가능한 바이트 배열(byte[])로 변환합니다. key.serializer, value.serializer 설정에 지정된 클래스가 이 역할을 수행합니다.
  3. 파티셔너(Partitioner): 메시지를 보낼 파티션을 결정합니다.
  4. 레코드 어큐뮬레이터(Record Accumulator): 직렬화된 메시지를 파티션별로 할당된 버퍼에 쌓아둡니다. 이는 메시지를 하나씩 보내는 대신, 여러 개를 묶어(배치) 한 번에 보내기 위함이며, 처리량을 극대화하는 핵심 요소입니다.
  5. 센더 스레드(Sender Thread): 별도의 백그라운드 스레드가 어큐뮬레이터에서 배치가 준비된 파티션의 레코드들을 가져와 브로커로 전송합니다. 배치는 batch.size에 도달하거나 linger.ms 시간이 초과되면 전송 준비가 완료됩니다.

핵심 설정 파라미터 딥다이브

프로듀서의 동작을 제어하는 가장 중요한 설정들을 통해 성능과 안정성을 튜닝할 수 있습니다.

1. 처리량과 지연시간: batch.sizelinger.ms

이 두 설정은 프로듀서의 배치(batch) 동작을 제어하여 처리량(Throughput)과 지연시간(Latency) 사이의 균형을 맞춥니다.

linger.ms > 0으로 설정하면, 레코드가 도착해도 즉시 보내지 않고 설정된 시간만큼 대기하면서 추가 레코드를 배치에 포함시키려 시도합니다. 이는 전송 횟수를 줄여 네트워크 오버헤드를 감소시키고 처리량을 향상시킵니다. 하지만 개별 메시지의 지연시간은 늘어나는 트레이드오프가 있습니다.

실무 트러블슈팅: 높은 CPU 사용량과 낮은 전송률

문제 상황: 대량의 로그를 카프카로 전송하는데, 프로듀서 애플리케이션의 CPU 사용량이 비정상적으로 높고 실제 전송률은 기대에 미치지 못합니다.

원인 분석: linger.ms가 기본값인 0으로 설정되어 있을 가능성이 높습니다. 이 경우, 프로듀서는 메시지가 발생할 때마다 개별적으로 전송을 시도하여 잦은 네트워크 I/O를 유발하고, 이는 CPU 사용량 증가와 처리량 저하로 이어집니다.

해결 방안: linger.ms를 5~100ms 사이의 값으로 설정하고, batch.size를 32KB~64KB로 상향 조정하여 배치의 효율을 높입니다. 이를 통해 전송 요청 횟수를 획기적으로 줄여 시스템 부하를 낮추고 전체 처리량을 개선할 수 있습니다.

2. 데이터 무결성: acks

acks 설정은 프로듀서가 보낸 메시지에 대해 브로커로부터 얼마나 신뢰도 높은 응답을 받을지 결정합니다. 이는 데이터 유실 방지와 직접적으로 연관됩니다.

acks 값 설명 장점 단점 주요 사용 사례
0 전송 후 응답을 기다리지 않음 (Fire-and-forget) 가장 빠른 속도, 최소한의 지연시간 네트워크 오류나 브로커 장애 시 메시지 유실 가능성 높음 유실되어도 무방한 비주요 지표, 대량의 로그 수집
1 리더 브로커에 저장되면 응답 받음 (기본값) 속도와 안정성의 적절한 균형 리더가 응답 직후, 팔로워에게 복제 전 장애 발생 시 데이터 유실 가능 일반적인 메시징 환경
all (-1) 리더와 모든 ISR(In-Sync Replicas)에 저장되면 응답 받음 가장 높은 데이터 내구성, 유실 가능성 최소화 (No Data Loss) 가장 느린 속도, 높은 지연시간 주문, 결제, 회원 정보 등 절대 유실되면 안 되는 핵심 데이터

실무 트러블슈팅: 간헐적인 주문 데이터 누락

문제 상황: 주문 서비스에서 주문 완료 메시지를 카프카로 전송했음에도 불구하고, 후속 처리 시스템에서 해당 주문이 간헐적으로 누락되는 현상이 발생합니다.

원인 분석: acks 설정이 기본값인 1로 되어 있을 가능성이 높습니다. 리더 브로커가 응답을 보낸 직후, ISR의 팔로워 브로커들에게 데이터를 복제하기 전에 장애가 발생하면 해당 데이터는 유실될 수 있습니다.

해결 방안: acks=all로 설정을 변경하여, 모든 동기화된 복제본에 데이터 저장이 완료된 것을 확인한 후에야 전송 성공으로 간주하도록 합니다. 이를 통해 데이터 유실을 원천적으로 방지할 수 있습니다.

3. 전송 재시도와 멱등성: retriesenable.idempotence

네트워크는 불안정할 수 있으며, 일시적인 오류로 메시지 전송이 실패할 수 있습니다. 카프카 프로듀서는 이러한 상황에 자동으로 대처하는 메커니즘을 제공합니다.

멱등성(Idempotence)이란?
동일한 연산을 여러 번 수행하더라도 결과가 단 한 번 수행한 것과 같은 상태를 의미합니다. 멱등성 프로듀서는 각 메시지에 고유한 시퀀스 번호를 부여하여, 브로커가 이미 처리한 시퀀스 번호의 메시지를 받으면 중복으로 저장하지 않고 폐기합니다.

acks=all, retries > 0, enable.idempotence=true 이 세 가지 조합은 데이터의 유실도, 중복도 없는 정확히 한 번 전송(Exactly-Once Semantics)을 보장하는 가장 강력하고 권장되는 설정입니다.

주요 프로듀서 예외(Exception)와 대응 방안

운영 환경에서 마주칠 수 있는 주요 예외와 그 원인, 해결책을 알아두는 것은 매우 중요합니다.

예외 클래스 발생 원인 대응 방안
TimeoutException 브로커로부터 정해진 시간(request.timeout.ms) 내에 응답을 받지 못함. 네트워크 문제, 브로커 과부하 등. retries 설정을 통해 자동 재시도. 지속 발생 시 브로커 상태 및 네트워크 점검.
RecordTooLargeException 전송하려는 메시지 크기가 브로커의 설정(message.max.bytes)보다 큼. 메시지 크기를 줄이거나, 브로커와 프로듀서의 최대 메시지 크기 설정을 상향 조정.
NotLeaderForPartitionException 리더십 변경으로 인해, 메시지를 보낸 브로커가 더 이상 해당 파티션의 리더가 아님. 프로듀서 클라이언트가 자동으로 메타데이터를 갱신하고 올바른 리더에게 재전송. 일반적으로 자동 해결됨.
UnknownTopicOrPartitionException 존재하지 않는 토픽이나 파티션으로 메시지를 보내려 함. 토픽 이름이 올바른지 확인. 토픽 자동 생성이 비활성화된 경우, 미리 토픽을 생성해야 함.