Tan Kim

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);
}

메모