Apache Kafka
분산 이벤트 스트리밍 플랫폼. 높은 처리량과 내구성을 가진 메시지 큐로, 서비스 간 비동기 통신과 이벤트 소싱에 사용된다.
핵심 개념
| 용어 |
설명 |
| Producer |
메시지를 발행(publish)하는 주체 |
| Consumer |
메시지를 구독(subscribe)하는 주체 |
| Topic |
메시지를 분류하는 논리적 채널 |
| Partition |
Topic을 물리적으로 분할한 단위 (병렬 처리) |
| Broker |
Kafka 서버 노드 |
| Consumer Group |
같은 Topic을 나눠서 소비하는 Consumer 집합 |
| Offset |
Partition 내 메시지 위치 (순서 보장) |
| Zookeeper / KRaft |
클러스터 메타데이터 관리 (KRaft는 Zookeeper 없이 동작) |
구조
Producer → Topic (Partition 0, 1, 2) → Consumer Group
├── Consumer A (Partition 0)
├── Consumer B (Partition 1)
└── Consumer C (Partition 2)
- Partition 수 ≥ Consumer 수일 때 병렬 처리 최대화
- 같은 Consumer Group 내에서 하나의 Partition은 하나의 Consumer만 담당
Kafka vs 일반 MQ
|
Kafka |
RabbitMQ 등 일반 MQ |
| 메시지 보관 |
기간 기반 (기본 7일) |
소비 후 삭제 |
| 재처리 |
Offset으로 가능 |
기본 불가 |
| 처리량 |
매우 높음 |
상대적으로 낮음 |
| 순서 보장 |
Partition 내에서 보장 |
Queue 단위 보장 |
| 용도 |
이벤트 스트리밍, 로그 수집 |
작업 큐, RPC |
Docker로 로컬 실행
# docker-compose.yml (KRaft 모드, Kafka 3.x+)
services:
kafka:
image: confluentinc/cp-kafka:latest
environment:
KAFKA_NODE_ID: 1
KAFKA_PROCESS_ROLES: broker,controller
KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
KAFKA_CONTROLLER_QUORUM_VOTERS: 1@localhost:9093
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
ports:
- "9092:9092"
주요 CLI
# Topic 생성
kafka-topics.sh --create --topic my-topic --partitions 3 --replication-factor 1 --bootstrap-server localhost:9092
# Topic 목록
kafka-topics.sh --list --bootstrap-server localhost:9092
# Producer (테스트용)
kafka-console-producer.sh --topic my-topic --bootstrap-server localhost:9092
# Consumer (테스트용)
kafka-console-consumer.sh --topic my-topic --from-beginning --bootstrap-server localhost:9092
Spring Boot 연동
# application.yml
spring:
kafka:
bootstrap-servers: localhost:9092
consumer:
group-id: my-group
auto-offset-reset: earliest
// Producer
@Service
public class EventProducer {
@Autowired
private KafkaTemplate<String, String> kafkaTemplate;
public void send(String topic, String message) {
kafkaTemplate.send(topic, message);
}
}
// Consumer
@KafkaListener(topics = "my-topic", groupId = "my-group")
public void consume(String message) {
System.out.println("Received: " + message);
}
메모