producer — 메시지를 topic에 보내는 주체

쇼핑몰 주문 API가 주문 이벤트를 orders topic에 넣는다(장 02). 이때 "메시지를 topic에 보내는 주체"가 producer다. 애플리케이션에 내장되는 클라이언트로, producer.send(...) 한 줄로 메시지를 쏜다.

이 글은 producer가 뭔지부터 시작해, 실제 설정과 코드로 어떻게 쓰는지, acks·idempotent producer로 신뢰성을 어떻게 확보하는지까지 다룬다.

producer란 — topic에 메시지를 보내는 클라이언트

producer는 앱에 내장되는 클라이언트 라이브러리다. 별도 서버가 아니라, 주문 API·배치 잡·로그 수집기 같은 앱 프로세스 안에서 동작한다.

Java producer 기본 코드

// 1. 설정
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("acks", "all");
props.put("enable.idempotence", "true");

// 2. producer 생성
Producer<String, String> producer = new KafkaProducer<>(props);

// 3. 메시지 전송
producer.send(new ProducerRecord<>("orders", "order-123", "주문 데이터"));

// 4. 종료
producer.close();

producer는 어떻게 쓰이나 — worked scenario

사용자가 "결제" 버튼을 누르면: 주문 API가 DB에 저장 → producer로 orders topic에 이벤트 전송 → 주문 처리·분석·알림 서비스가 각자 소비(장 02 시나리오).

flowchart LR
    U[결제 클릭] --> API[주문 API]
    API -->|1. DB 저장| DB[(주문 DB)]
    API -->|2. producer.send| P[producer]
    P -->|메시지| T[orders topic]
    T --> C1[주문 처리]
    T --> C2[분석]

send는 비동기다 — 즉시 반환, 뒤에서 전송

send()비동기. 즉시 Future를 반환하고, 실제 전송은 배경 스레드(sender)가 처리. 애플리케이션이 broker 응답을 기다리며 멈추지 않도록 한다.

flowchart LR
    A["send(record)"] --> ACC["accumulator<br/>(batch 모음)"]
    ACC --> SND["sender 스레드<br/>(배경 전송)"]
    SND --> L["broker"]

send 콜백으로 성공/실패 확인

producer.send(new ProducerRecord<>("orders", "order-123", "data"), (metadata, exception) -> {
    if (exception == null) {
        System.out.println("전송 성공: " + metadata.partition() + "/" + metadata.offset());
    } else {
        System.err.println("전송 실패: " + exception.getMessage());
    }
});

batch — 왜 모아서 보내는가

메시지를 하나씩 보내지 않고 여러 개를 batch로 모아 보낸다. linger.ms(대기)나 batch.size(크기)에 도달하면 전송. 네트워크 왕복 비용을 줄인다.

batch는 압축과 짝 — batch로 뭉쳐야 압축 효율이 올라간다. linger.ms=0 + 압축은 무의미(메시지 1개씩이라 압축 안 걸림).

acks — "얼마나 확실히 썼다고 볼 것인가"

acks 의미 신뢰성 언제
0 확인 안 기다림 가장 낮음 손실 감내 로그
1 리더까지만 확인 중간 성능 우선
all(-1) 리더 + ISR 전원 확인 가장 높음 신뢰성 필수

acks=allmin.insync.replicas(예: 2)와 세트여야 의미 — ISR이 1개면 사실상 신뢰성 없음. 프로덕션 표준: replication.factor=3, min.insync.replicas=2, acks=all(장 06).

idempotent producer — 재시도해도 중복이 안 생기는 비밀

재시도를 켜면 같은 메시지가 두 번 쓰일 수 있다. idempotent producer는 broker가 중복을 걸러낸다:

  • enable.idempotence=true → broker가 PID 발급 → 각 메시지에 sequence number → 중복 검출.

4.x 기본값은 true. 구형 자료(false 기본)와 혼동 주의.

idempotent 모드는 acks=all, retries>0, max.in.flight<=5를 자동 강제.

producer.properties — 전체 설정 예제

신뢰성 우선 (프로덕션 권장)

# 연결
bootstrap.servers=localhost:9092

# 직렬화
key.serializer=org.apache.kafka.common.serialization.StringSerializer
value.serializer=org.apache.kafka.common.serialization.StringSerializer

# 신뢰성
acks=all
enable.idempotence=true
retries=2147483647
max.in.flight.requests.per.connection=5

# 배치/처리량
linger.ms=10
batch.size=16384
compression.type=zstd

# 재시도 상한 (총)
delivery.timeout.ms=120000
request.timeout.ms=30000

처리량 우선 (로그 수집)

acks=1
linger.ms=50
batch.size=131072
compression.type=zstd

→ 지연 수십 ms 희생, 처리량·네트워크 효율 최대.

지연 최소 (실시간 이벤트)

acks=1
linger.ms=0
compression.type=none

→ 처리량 희생, end-to-end 지연 최소.

Kafka 4.3 실습 — 직접 확인하기

console-producer

# Kafka 4.3, KRaft 단일 노드
bin/kafka-console-producer.sh --topic prod-demo --bootstrap-server localhost:9092
>Hello
>World

확인할 것: 각 줄이 topic에 메시지로 들어감. 다른 터미널에서 consumer로 읽어 확인.

key와 함께 produce

bin/kafka-console-producer.sh --topic prod-demo \
  --property "parse.key=true" --property "key.separator=:" \
  --bootstrap-server localhost:9092
# userA:evt1 / userA:evt2 / userB:evt3

확인할 것: 같은 key는 같은 partition으로 감(장 02).

흔히 묻는 것, 흔히 틀리는 것

오해 정정
"producer는 별도 서버다" 앱에 내장되는 클라이언트
"send() 반환됐으면 broker에 도달했다" 비동기. accumulator에 있을 수 있음
"acks=1이면 안전하다" 리더 장애 시 미복제 손실 위험
"재시도하면 무조건 중복" idempotent(4.x 기본)는 broker가 제거
"linger.ms=0이 항상 빠르다" 지연은 최소지만 처리량은 낮음
"4.x도 idempotence=false 기본" 아니다. 4.x는 기본 true
"압축은 producer만 손해" broker가 압축된 채 저장·전송

더 깊이

  • max.in.flight와 순서: 1보다 크면 재시도 시 순서 뒤바뀔 수 있음. idempotent 모드는 5 이하로 제한해 순서 보존.
  • delivery.timeout.ms: 총 재시도 상한(기본 2분). 시간 기반 모델(무한 retries 아님).
  • transactional producer: transactional.id로 여러 partition 원자 쓰기 → EOS(장 08).
  • JMX metrics: record-send-rate, retry-rate(높으면 불안정), batch-size-avg.

요약 — 이 글의 결론

  • producer = 앱 내장 클라이언트. send()로 topic에 메시지.
  • 비동기 send: accumulator→sender 배경 전송. 콜백으로 성공/실패 확인.
  • batch: linger.ms/batch.size로 모아 효율↑. 압축과 세트.
  • acks: 0/1/all. allmin.insync.replicas와 세트.
  • idempotent producer(4.x 기본): PID+sequence로 중복 제거 + 순서 보존.
  • 설정 프로필: 신뢰성 우선(acks=all+idempotent) / 처리량 우선(linger 큼) / 지연 최소(linger=0).

생각해 볼 문제

  1. producer가 "앱 안의 클라이언트"라는 것이 운영상 어떤 의미인가?
  2. send()가 비동기인 것을 어떻게 확인하는가? (콜백)
  3. acks=0/1/all의 차이를 복제 관점에서 설명하라.
  4. idempotent producer가 중복을 어떻게 제거하는가? 4.x 기본값은?
  5. 신뢰성 우선 producer.properties를 작성해 보라.
  6. linger.ms=0 + compression이 무의미한 이유는?

참고

'Tech Artifacts > Kafka' 카테고리의 다른 글

Kafka - 06. replication  (0) 2026.07.09
Kafka - 05. consumer group  (0) 2026.07.09
Kafka - 04. consumer  (0) 2026.07.09
Kafka - 02. topic and partition  (0) 2026.07.09
Kafka - 01. architecture  (0) 2026.07.09