Posts 카프카 개요
Post
Cancel

카프카 개요

카프카란 ?


공식 사이트에서는 “Apache Kafka is an open-source distributed event streaming platform“라고 표현

아래는 카프카 에코시스템 구성도로, 외부 시스템을 제외한 모든 게 Apache Kafka 에코시스템에 포함된다.

단, Schema Registry와 일부 Connect 커넥터 등은 Confluent 제품이며 Apache Kafka 코어에는 포함되지 않는다.

카프카 에코시스템 구성도

Kafka 에코시스템 구성도 - Producers, Brokers, Consumers, Streams, Connect와 외부 시스템

이벤트란 ?


“어떤 일이 일어났다”는 사실의 기록

  • Producer가 보내는 이벤트는 네 가지 요소로 구성:
    • key파티셔닝의 기준 (같은 key → 같은 파티션 → 순서 보장). 분류 자체는 토픽이 담당
    • value — 실제 내용
    • timestamp — 발생 시각
    • headers — 부가 정보 (선택)
  • Kafka가 추가로 부여하는 식별자:
    • partition, offset — 메시지의 위치를 유일하게 식별 (replay·재처리의 기준)

이벤트 예시

주문 도메인에서 발행되는 OrderCreated 이벤트를 예로 들면 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
key       : "order-1001"                        // 같은 주문ID는 같은 파티션 → 순서 보장
value     : {
              "orderId": "order-1001",
              "userId": "user-42",
              "amount": 59000,
              "items": [{ "sku": "A-1", "qty": 2 }]
            }
timestamp : 2026-05-24T22:13:21.096+09:00
headers   : {
              "event-type":     "OrderCreated",
              "schema-version": "v3",
              "trace-id":       "9f1c...e2"
            }

// ↓ Kafka가 부여
topic     : "order-events"
partition : 4
offset    : 28173
  • key를 orderId로 두는 이유 : 같은 주문에 대한 후속 이벤트(OrderPaid, OrderShipped)가 동일 파티션에 적재되어 순서가 보장
  • headers의 용도 : event-type, schema-version, trace-idvalue를 역직렬화하지 않고도 라우팅/필터링/관측에 쓸 수 있는 메타정보
  • value 포맷 : 위 예시는 JSON이지만 실무에서는 Avro / Protobuf가 자주 쓰임 (아래 “이벤트 포맷” 참고)

이벤트 포맷

브로커는 페이로드(value)에 관여하지 않는다. 직렬화/역직렬화·스키마 검증은 모두 Producer/Consumer의 몫이다.

  • 따라서 어떤 포맷을 쓸지는 전적으로 Producer와 Consumer가 합의해야 함
  • 다만 실무에서는 합의를 코드/문서로만 유지하기 어렵기 때문에, Schema Registry(Confluent 제품)를 함께 쓰는 경우가 많음
    • Avro / Protobuf / JSON Schema 로 스키마를 등록하고, Producer/Consumer가 동일 스키마를 참조하도록 강제
    • 스키마 호환성 규칙(BACKWARD / FORWARD / FULL)으로 스키마 진화(evolution) 를 안전하게 관리
    • 메시지에는 실제 스키마 대신 스키마 ID만 포함되어 페이로드 크기도 절감

포맷별 특징을 정리하면 다음과 같다.

포맷장점단점
JSON사람이 읽기 쉬움, 디버깅 편함용량 큼, 스키마 강제 어려움
Avro컴팩트, 스키마 진화 강력, Kafka 생태계 표준사람이 읽기 어려움, Schema Registry 의존
Protobuf컴팩트, gRPC와 궁합 좋음, 다언어 지원진화 규칙 학습 필요
  • 정리:
    • 브로커 관점 : 페이로드는 그냥 바이트 → 포맷에 무관
    • 생태계 관점 : Schema Registry로 포맷·스키마를 계약(contract) 으로 강제하는 게 일반적

이벤트 스트리밍


데이터베이스, 센서, 모바일 기기 등에서 발생하는 데이터를 실시간으로 캡처하고, 저장하고, 처리하고, 필요한 곳으로 라우팅하는 기술

  • 이벤트 스트리밍 플랫폼이라고 부르는 건, 단순히 이벤트를 전달하는 브로커 역할을 넘어서 네 가지를 다 하기 때문:
    • 캡처 : Producer API로 이벤트 발행(publish)
    • 저장 : 토픽에 이벤트를 retention 정책(기본 7일, retention.ms / retention.bytes / compaction) 에 따라 보관
    • 라우팅 : 토픽 구독 모델로 여러 서비스에 전달
      • 서로 다른 Consumer Group은 같은 데이터를 각자 독립적으로 모두 수신
      • 한 Consumer Group 내부에서는 파티션 단위로 분배 (= 워크로드 분산)
      • ⚠ RabbitMQ exchange처럼 “메시지 내용 기반 라우팅”이 아님
    • 처리 : Kafka Streams(Apache Kafka 포함)로 스트림 데이터를 직접 가공
      • ksqlDB로도 가능하나, 이는 Confluent 제품이며 Apache Kafka 코어에는 포함되지 않음
      • ex : order 토픽 → 필터(5만원 이상) → vip-order 토픽
      • 토픽에서 토픽으로 데이터가 흐르면서 가공되는 파이프라인을 Kafka 자체적으로 만들 수 있음
  • 즉, Kafka는 데이터를 수집하고, 보관하고, 흘려보내고, 가공까지 하는 통합 플랫폼

왜 events가 아닌 streams of events라고 표현할까 ?


공식 문서 : “To publish (write) and subscribe to (read) streams of events …”

  • 일반적인 메시지 큐 (예: RabbitMQ)는 이벤트를 소비(ack) 시점에 큐에서 제거하는 구조
    • Consumer가 메시지를 받고 ack하면 큐에서 사라짐 (ack 안 하면 다른 Consumer에게 재전달)
    • 관심사는 “이 메시지를 누군가 처리했는가”
    • fanout exchange 등으로 멀티 컨슈머 브로드캐스트는 가능하지만, 이미 소비된 메시지를 과거 시점부터 다시 읽는 개념은 없음
  • Kafka는 이벤트를 흐름 자체로 보존하는 구조 (retention 기간 내)
    • Consumer가 읽어도 데이터는 그대로 남아있고, 여러 Consumer Group이 같은 흐름을 각자 다른 offset부터 읽을 수 있음
    • 소비 위치(offset)는 Consumer 측이 관리 → 브로커는 “누가 어디까지 읽었는지”에 관여하지 않음
  • 그래서 Kafka가 “streams of events”라고 표현한 진짜 의미는 단순히 “이벤트가 연속으로 온다”가 아니라, 연속된 흐름 자체를 하나의 데이터로 보존하고 다룬다는 뜻
  • 이 차이 때문에 Kafka에서는 “어제 들어온 주문 흐름을 처음부터 다시 재생(replay)”하는 게 가능 (단, retention 기간 내의 데이터에 한함)

탄생 배경 & 핵심 개념


LinkedIn에서 2010년경 Jay Kreps · Neha Narkhede · Jun Rao가 설계. 회원·콘텐츠·활동 데이터가 폭증하면서 데이터 파이프라인 자체가 가장 큰 부채가 된 상황을 풀기 위해 출발.

문제 → 해결 매핑

#문제당시 상황해결 방안 (핵심 개념)비고 (링크 / 핵심 인용)
P1N×M 파이프라인 폭발source N개 × sink M개 → 통합 코드 N×M개. 시스템 추가될 때마다 모든 곳을 손봐야 함① 토픽 기반 Pub/Sub — Producer는 토픽에 발행, Consumer는 토픽을 구독. 양쪽이 서로를 모름 → 통합 비용이 N+M으로 떨어짐Introduction
The Log (Kreps)
P2소비 후 사라짐전통 MQ(ActiveMQ, RabbitMQ)는 ack 시 메시지 삭제 → 같은 데이터를 분석·모니터링·검색에 재사용 불가② 로그 영속성 + Offset 기반 소비 — append-only log에 영구 저장, offset은 Consumer가 관리. 여러 Consumer가 각자 다른 시점부터 읽기/replay 가능Design §4.5 Consumer — Consumer Position
💬 “the consumer simply falls behind and catches up when it can” (§ Push vs. pull)
P3실시간 ↔ 배치 파이프라인 이중화OLTP DB는 백로그 적재용, MQ는 실시간용 → 같은 데이터를 두 번 파이프해야 했음③ 로그 = Storage System — retention 정책으로 시간/용량 단위 보존(무제한도 가능). 같은 토픽을 실시간 스트림 처리 + 배치 적재에 동시 사용Use Cases
The Log (Kreps) — 이 글의 핵심 주장
P4단일 노드 처리량 한계활동 로그·메트릭 같은 대량 이벤트는 단일 브로커로 감당 불가④ 파티션 + Consumer Group — 토픽을 파티션 N개로 쪼개 여러 브로커에 분산. Consumer Group 내에서 파티션을 분배해 병렬 소비. key 기반 파티셔닝으로 순서도 함께 보장Introduction § Main Concepts — 파티션·Consumer Group 정의
Design §4.5 Consumer — Consumer Group 동작
P5Push 모델의 위험빠른 producer가 느린 consumer를 죽임 (back-pressure 부재)⑤ Pull 모델 — Consumer가 자기 페이스로 broker에서 pull. 자연스러운 back-pressure 확보Design §4.5 Consumer — Push vs. pull
P6장애 시 데이터 손실단일 브로커 장애 = 메시지 손실. fault-tolerance가 부수 기능 수준⑥ Replication (Leader/Follower + ISR) — 파티션 단위 leader 1 + follower N 복제. leader를 거의 따라잡은 replica 집합 = ISR(In-Sync Replicas)Design §4.7 Replication
💬 “a committed message will not be lost, as long as there is at least one in sync replica alive.”
P7“디스크는 느리다”는 통념빠른 처리를 위해 in-memory MQ 외 선택지 없어 보임 → 영속성 vs 성능 trade-off⑦ 순차 I/O + Page Cache + Zero-Copy + 배칭 — 순차 디스크 쓰기 / OS page cache 활용(JVM heap 절약) / sendfile로 복사 없이 네트워크 전송 / Producer·Broker·Consumer 공유 바이너리 포맷으로 배칭 → 디스크 기반인데도 메모리 MQ급 처리량Design §4.2 Persistence
Design §4.3 Efficiency
💬 “All data is immediately written to a persistent log on the filesystem without necessarily flushing to disk.”

참고 자료


This post is licensed under CC BY 4.0 by the author.

부하 테스트, 어떻게 주고 어떻게 읽을 것인가

카프카 프로듀서에서 컨슈머까지의 처리 흐름