Kafka Shallow Dive - Kafka는 왜 쓰는가

Published:

Kafka를 제대로 들여다보기로 했다. 이름만 알고 썼다가 장애 한 번 맞으니 속이 허해져서, 10주짜리 커리큘럼을 짰다. 첫 주는 “Kafka가 뭐고 왜 쓰는가”.

Kafka ?

분산 이벤트 스트리밍 플랫폼. 이름이 길지만 뜯어보면 3가지다.

  • 분산(Distributed) - 여러 서버(브로커)가 클러스터로 묶여 동작
  • 이벤트(Event) - “무슨 일이 언제 일어났다”는 사실(fact)을 기록
  • 스트리밍(Streaming) - 끝없이 이어지는 이벤트 흐름을 실시간으로 처리

즉, “여러 서버에 걸쳐서 이벤트 로그를 쌓고 흘려보내는 시스템”.

왜 만들어졌나

LinkedIn이 2010년경에 만듦. 당시 문제:

  • 서비스가 수십 개인데 서로 데이터를 주고받아야 함 (검색, 추천, 모니터링, DW 등)
  • 각 서비스마다 별도 파이프라인 만들다 보니 N×M 연결지옥
  • 실시간 분석도 하고 싶은데 배치로만 돌고 있음
[App1] → [Search]
     ↘ [Analytics]
     ↘ [Monitoring]
     ↘ [DW]
[App2] → [Search]
     ↘ [Analytics]
     ...

해결책으로 “중앙 로그(central log)” 컨셉 도입. 모든 이벤트를 Kafka에 던지면, 필요한 쪽이 가져다 읽음.

[App1] ↘                    ↗ [Search]
[App2] → [ Kafka (logs) ] → [Analytics]
[App3] ↗                    ↘ [DW]

N×M이 N+M으로 줄어들고, 새 consumer를 추가해도 producer는 안 바꿔도 된다.

기존 메시지 큐랑 뭐가 다름?

RabbitMQ, ActiveMQ 같은 전통 메시지 큐가 이미 있는데 왜 Kafka?

구분전통 MQ (RabbitMQ 등)Kafka
모델Queue (consume 시 삭제)Log (append-only, 보존)
라우팅Exchange/Queue 복잡Topic/Partition 단순
메시지 보존소비되면 사라짐시간/용량 기반 보존
재처리어렵거나 불가offset 되감기로 재처리 가능
처리량수만/초수십만~수백만/초
순서 보장큐 단위파티션 단위
용도작업 분배, RPC-like이벤트 로그, 스트리밍

포인트는 “소비 = 삭제”가 아니라 “소비 = 읽기” 라는 것. Kafka는 메시지를 로그처럼 append-only로 쌓고, consumer는 자기 위치(offset)만 기억하면 됨. 같은 데이터를 여러 consumer가 각자 속도로 읽을 수 있고, 필요하면 과거 시점으로 되감을 수도 있다.

어떤 문제에 쓰는가

대표적인 유스케이스:

  • 로그/메트릭 수집 - 앱 수백 대에서 나오는 로그를 한 곳으로 모음
  • 이벤트 소싱 - 상태를 DB에 저장하는 대신 이벤트로 기록 (감사, 재구성 용이)
  • CDC(Change Data Capture) - DB 변경분을 실시간으로 빼서 다른 시스템에 전파
  • 실시간 분석 - 클릭스트림/IoT 데이터를 Kafka Streams/Flink로 처리
  • 마이크로서비스 간 비동기 통신 - 서비스가 이벤트만 발행하고 나머진 subscribe

반대로 Kafka가 부적절한 경우도 있음:

  • 요청/응답 패턴(RPC) — gRPC나 HTTP가 낫다
  • 개별 메시지마다 복잡한 우선순위/지연 큐가 필요한 경우 — RabbitMQ가 낫다
  • 초저지연(수 ms) — 가능은 하지만 Kafka의 강점은 처리량 쪽

핵심 용어 한 장 요약

이번 주는 이 정도만 잡고 가자. 다음 주에 파고든다.

  • Broker - Kafka 서버 한 대. 여러 대 모아서 클러스터
  • Topic - 이벤트를 분류하는 논리적 이름 (e.g. orders, clicks)
  • Partition - Topic을 나눈 물리적 로그. 병렬성의 단위
  • Offset - Partition 안에서 메시지의 위치 (0부터 증가)
  • Producer - 이벤트를 topic에 쓰는 쪽
  • Consumer - 이벤트를 topic에서 읽는 쪽
  • Consumer Group - 같은 topic을 나눠 읽는 consumer 묶음

설치 & 첫 메시지

로컬에서 그냥 한 번 띄워봄. Confluent에서 제공하는 Docker Compose가 제일 편함.

# docker-compose.yml (최소)
services:
  kafka:
    image: apache/kafka:3.7.0
    ports:
      - "9092:9092"
    environment:
      KAFKA_NODE_ID: 1
      KAFKA_PROCESS_ROLES: broker,controller
      KAFKA_LISTENERS: PLAINTEXT://:9092,CONTROLLER://:9093
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
      KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
      KAFKA_CONTROLLER_QUORUM_VOTERS: 1@localhost:9093
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      CLUSTER_ID: "MkU3OEVBNTcwNTJENDM2Qk"
docker compose up -d

# topic 생성
docker compose exec kafka \
  kafka-topics.sh --bootstrap-server localhost:9092 \
  --create --topic hello --partitions 1 --replication-factor 1

# 메시지 쓰기
docker compose exec -it kafka \
  kafka-console-producer.sh --bootstrap-server localhost:9092 --topic hello

# 메시지 읽기 (다른 터미널)
docker compose exec kafka \
  kafka-console-consumer.sh --bootstrap-server localhost:9092 \
  --topic hello --from-beginning

--from-beginning을 빼면 consumer 실행 이후의 메시지만 받는다. 이게 offset의 첫 느낌.

정리

Kafka는 “분산된 append-only 로그”로 요약됨. 큐가 아니라 로그라서 여러 소비자가 독립적으로 읽고 되감을 수 있고, 그 특성 덕분에 실시간 파이프라인의 허브로 자리잡음. 왜 썼는지도 모르고 YAML만 복붙했던 지난 주와 달리, 이제 “로그로 쌓는다”는 문장이 감이 온다.

다음 주는 내부 구조 — Broker/Topic/Partition이 어떻게 파일시스템 위에 올라가 있는지.