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=all은 min.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.all은min.insync.replicas와 세트.- idempotent producer(4.x 기본): PID+sequence로 중복 제거 + 순서 보존.
- 설정 프로필: 신뢰성 우선(acks=all+idempotent) / 처리량 우선(linger 큼) / 지연 최소(linger=0).
생각해 볼 문제
- producer가 "앱 안의 클라이언트"라는 것이 운영상 어떤 의미인가?
- send()가 비동기인 것을 어떻게 확인하는가? (콜백)
acks=0/1/all의 차이를 복제 관점에서 설명하라.- idempotent producer가 중복을 어떻게 제거하는가? 4.x 기본값은?
- 신뢰성 우선 producer.properties를 작성해 보라.
linger.ms=0+ compression이 무의미한 이유는?
참고
- Producer configs (producer-configs.txt) - 접근 2026-07-09
- ProducerConfig.java (idempotence/delivery.timeout) - 접근 2026-07-09
- KIP-98(idempotent producer/transactions), KIP-588(zombie fencing)
'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 |
