6단계
Kafka — 언제 · 언제 아닌지
30 분
Kafka — 언제 · 언제 아닌지
Kafka 는 강력하지만 운영 비용도 큽니다. 도입 전에 "진짜 필요한가?" 를 점검.
1. Kafka 가 진짜 해결하는 문제
- 이벤트 로그 영구 보관 — 소비자가 언제든 과거부터 재생
- 여러 소비자가 같은 스트림 소비 — fan-out
- 초고속 쓰기 · 순서 보장 (partition 단위)
- 서비스 간 decoupling — producer 가 consumer 를 몰라도 됨
2. Kafka 가 아닌 경우
- 작업 큐 (한 소비자) — BullMQ · Redis Streams · RabbitMQ 가 가볍고 충분
- Pub/Sub (메시지 휘발 OK) — Redis Pub/Sub
- 단순 DB 비동기 쓰기 — outbox 패턴 + 단일 worker
- 트래픽 < 100 msg/s — Kafka 운영 부담이 이득 초과
3. 토픽 · 파티션 · 오프셋
Topic: user-events
├── Partition 0 ── offset 0, 1, 2, 3, 4 ...
├── Partition 1 ── offset 0, 1, 2, 3, 4 ...
└── Partition 2 ── offset 0, 1, 2, 3, 4 ...
- Topic — 이벤트 채널
- Partition — 순서 보장 단위 · 병렬성 단위
- Offset — 파티션 내 위치
파티션 수 = 최대 병렬 소비자 수.
4. Producer
import { Kafka } from "kafkajs";
const kafka = new Kafka({ clientId: "app", brokers: ["kafka:9092"] });
const producer = kafka.producer();
await producer.connect();
await producer.send({
topic: "user-events",
messages: [
{ key: String(userId), value: JSON.stringify({ type: "signup", userId, at: Date.now() }) },
],
});
key 가 같으면 같은 partition 으로 라우팅 (순서 보장 필요 시).
5. Consumer
const consumer = kafka.consumer({ groupId: "notifier" });
await consumer.connect();
await consumer.subscribe({ topic: "user-events", fromBeginning: false });
await consumer.run({
eachMessage: async ({ topic, partition, message }) => {
const payload = JSON.parse(message.value!.toString());
await handleEvent(payload);
},
});
groupId— 같은 그룹은 파티션 분배, 다른 그룹은 모두 수신fromBeginning: true— 처음부터 재생- 커밋 — 기본 auto-commit, 실패 시 재처리 원하면 수동
6. 토픽 네이밍
<domain>.<entity>.<action>
user.signed-up
order.placed
payment.succeeded
혼재 금지. 다른 언어 · 다른 팀과 합의 필수.
7. 이벤트 스키마
JSON vs Avro · Protobuf.
- JSON — 시작하기 쉬움 · 스키마 강제 없음
- Avro (Confluent Schema Registry) — 스키마 버전 관리
- Protobuf — 타입 · 언어 크로스
MVP JSON → 운영 안정화 후 Schema Registry 도입이 자연스러움.
8. 백프레셔
소비자가 producer 를 못 따라가면 lag 증가.
Topic lag = producer offset - consumer offset
대응:
- 소비자 인스턴스 추가 (파티션 수 내에서)
- 무거운 작업은 별도 워커로 위임
- dead-letter topic 으로 문제 메시지 격리
9. 운영 비용
- Confluent Cloud — 관리형 · 최소 $50 ~ 200/월
- Self-hosted — ZooKeeper 또는 KRaft + Kafka 3 노드 권장 · 운영 복잡
- AWS MSK — 관리형 · 시간당 과금
작은 팀은 관리형 추천.
10. 자주 걸리는 자리
- 파티션 수 나중에 늘릴 때 순서 보장 깨짐 — 처음부터 넉넉히 (배수로 늘리기 쉽게)
- key 없이 producer.send — 라운드 로빈. 순서 보장 없음
- consumer 그룹 ID 공유 실수 — 두 앱이 같은 ID 면 메시지 분배됨
- 커밋 타이밍 — 처리 성공 후 커밋. 실패 시 재처리 로직
하고픈 말
첫 메시징 시스템은 BullMQ · Redis Streams 로 시작하고, 진짜 fan-out · replay 가 필요해지는 시점에 Kafka 도입이 자연스럽습니다.
Next
- 07-pipeline-idempotency