학습 목표

왜 Kafka인가 — 메시지 큐가 아니라 로그입니다

시스템이 늘어나면 데이터 이동 경로가 곱셈으로 늘어납니다. 주문 서비스가 재고·정산·알림·분석에 각각 직접 연결하면 연결선은 서비스 수의 곱에 비례해 늘고, 새 소비자를 추가할 때마다 생산자 쪽을 고쳐야 합니다. Kafka는 그 사이에 durable한 로그를 하나 두어 생산자와 소비자를 완전히 분리합니다. 공식 문서는 이를 세 가지 능력의 조합으로 정의합니다.

  1. 이벤트 스트림을 발행(publish)하고 구독(subscribe)한다.
  2. 이벤트 스트림을 원하는 기간만큼 durable하고 신뢰성 있게 저장한다.
  3. 이벤트 스트림을 발생 시점에 또는 사후에 처리한다.

두 번째 항목이 전통적 메시지 큐와 결정적으로 다른 지점입니다. Kafka에서 이벤트는 소비되어도 삭제되지 않습니다. 보관 기간은 토픽별 설정으로 정하고, 그 기간이 지난 이벤트만 버려집니다. 읽기 위치는 브로커가 아니라 소비자 쪽 오프셋이 결정하므로, 같은 데이터를 여러 소비자가 각자의 속도로, 필요하면 처음부터 다시 읽을 수 있습니다.

메시지 큐와 분산 커밋 로그의 차이 — 소비 후 삭제 대 로그 유지와 오프셋 왼쪽은 전통적 메시지 큐입니다. 프로듀서가 m1, m2, m3 를 넣고 컨슈머 A 가 m1 을 꺼내면 큐에서 m1 이 삭제되어 컨슈머 B 는 그 메시지를 다시 볼 수 없고 재처리도 불가능합니다. 오른쪽은 Kafka 의 분산 커밋 로그입니다. 레코드는 로그 끝에 덧붙여지고 오프셋 0부터 7까지 그대로 남습니다. 그룹 A 는 오프셋 3, 그룹 B 는 오프셋 6 처럼 그룹마다 읽은 위치를 따로 가지므로 여러 소비자가 같은 로그를 각자의 속도로 읽을 수 있고, 오프셋을 0으로 되돌리면 처음부터 다시 처리할 수 있습니다. 삭제 시점은 소비 여부가 아니라 retention 설정이 결정합니다. 메시지 큐 vs 분산 커밋 로그 — 읽은 뒤에 남는지가 갈린다 전통적 메시지 큐 — 꺼내면 사라집니다 Kafka 분산 커밋 로그 — 읽어도 남습니다 1) 프로듀서가 3건 전송 m1 m2 m3 2) 컨슈머 A 가 m1 을 꺼냄 m1 m2 m3 3) 큐에서 m1 은 삭제 m2 m3 컨슈머 B 는 m1 을 볼 수 없습니다. 같은 메시지를 다른 용도로 한 번 더 쓰거나 어제 데이터를 다시 처리하는 것이 구조적으로 불가능합니다. 1) 로그 끝에 append 0 1 2 3 4 5 6 7 2) 그룹 A 는 오프셋 3 0 1 2 3 4 5 6 7 3) 그룹 B 는 오프셋 6 0 1 2 3 4 5 6 7 같은 로그를 그룹마다 다른 위치에서 읽습니다. 오프셋을 0 으로 되돌리면 처음부터 재처리하고, 삭제 시점은 소비 여부가 아니라 retention 설정이 정합니다. 진한 칸 = 그 그룹이 이미 읽고 커밋한 구간 핵심: 큐는 "전달하고 지우는" 모델, Kafka 는 "쌓아 두고 각자 위치를 기억하는" 모델입니다.
메시지 큐 vs 분산 커밋 로그 — 소비 후 삭제되는 큐와, 로그에 남고 오프셋으로 위치를 관리하는 Kafka의 좌우 비교

비교표

전통적 메시지 큐(브로커 중심 소비 모델)와 Kafka의 로그 모델 비교
관점 전통적 메시지 큐 Kafka (분산 커밋 로그)
소비 후 데이터 큐에서 제거됨 보관 기간까지 그대로 남음
읽기 위치 관리 브로커가 각 메시지의 배달 상태를 추적 소비자 그룹의 오프셋으로 관리
재처리 일반적으로 불가 (별도 보관 필요) 오프셋을 되돌려 다시 읽으면 됨
다중 소비자 같은 메시지를 여러 소비자에게 주려면 팬아웃 구조 필요 소비자 그룹마다 독립적으로 전체를 읽음
순서 보장 단위 큐 전체 또는 없음 파티션 단위로 보장
확장 방식 큐/브로커 추가 파티션 추가 → 생산·소비 병렬성 증가

핵심 추상 — 이벤트, 토픽, 파티션, 오프셋

토픽과 파티션

이벤트는 토픽(topic)에 저장됩니다. 토픽은 파일시스템의 폴더에 가깝고, 이벤트가 그 안의 파일에 해당합니다. 토픽은 항상 다중 생산자·다중 구독자이며, 생산자 0개 이상, 소비자 0개 이상이 붙을 수 있습니다.

토픽은 여러 파티션(partition)으로 쪼개져 서로 다른 브로커에 배치됩니다. 이 분산 배치가 확장성의 근거입니다. 클라이언트가 여러 브로커에 동시에 읽고 쓸 수 있기 때문입니다. 새 이벤트를 토픽에 발행하면 실제로는 그중 한 파티션의 끝에 append됩니다.

같은 키를 가진 이벤트는 같은 파티션에 기록됩니다. 그리고 Kafka는 특정 토픽-파티션의 소비자가 그 파티션의 이벤트를 기록된 순서 그대로 읽는 것을 보장합니다. 순서 보장이 파티션 단위인 이유가 여기 있습니다. 주문 ID를 키로 쓰면 그 주문의 상태 변화가 뒤바뀌지 않습니다. 키를 지정하지 않으면 순서 보장의 근거 자체가 사라집니다 — 이 실수의 결과는 케이스 4에서 다룹니다.

오프셋 — 파티션 안의 좌표

오프셋(offset)은 파티션 안에서 레코드의 위치를 나타내는 단조 증가 정수입니다. 파티션에 append될 때 부여되고, 이후 변하지 않습니다. 오프셋은 파티션 안에서만 의미가 있습니다. 토픽 전체를 가로지르는 전역 오프셋은 존재하지 않습니다.

실무와 시험에서 가장 많이 혼동되는 것은 오프셋이 한 종류가 아니라는 점입니다. 하나의 파티션 로그 위에 최소 네 개의 서로 다른 지점이 동시에 존재합니다. 아래 다이어그램의 슬라이더를 움직여 이 네 지점이 어떻게 벌어지는지 확인해 보세요. 복제·ISR과 함께 보는 상세한 설명은 2장 아키텍처와 핵심 개념에 있습니다.

오프셋 4종 구분 — log-start-offset · committed offset · high watermark · LEO 하나의 파티션 로그를 12칸 막대로 표현한 그림입니다. 리더 로그 위에 네 지점이 표시됩니다. log-start-offset은 리텐션으로 삭제된 경계, committed offset은 컨슈머 그룹이 커밋한 위치, high watermark는 ISR 내 모든 레플리카가 복제를 마쳐 컨슈머가 읽을 수 있는 상한, LEO는 리더가 기록한 마지막 위치입니다. committed offset과 high watermark 사이는 아직 읽지 않은 구간이고, high watermark와 LEO 사이는 복제가 끝나지 않아 컨슈머에게 보이지 않는 구간입니다. 아래에는 팔로워 두 대의 복제 진행 막대가 있으며, high watermark가 그중 최소 LEO에 맞춰지는 것을 점선으로 잇습니다. 리더 (broker-1) 의 파티션 로그 — orders-0 LEO 12 HW 7 0 1 2 3 4 5 6 7 8 9 10 11 리더 아직 안 읽음 3건 아직 복제 안 됨 5건 시작 0 커밋 4 팔로워 복제 진행 (ISR 멤버) — high watermark 는 이 중 최소 LEO 로 결정 팔로워 B LEO 9 팔로워 C LEO 7 high watermark = ISR 내 최소 LEO → 팔로워 C(7) 시작 = log-start-offset (리텐션 삭제 경계) 커밋 = committed offset (컨슈머 그룹) HW = high watermark (읽기 가능 상한) LEO = log end offset (리더 기록 끝) 읽고 커밋함 읽을 수 있음 복제 미완 · 안 보임 미기록 삭제됨 컨슈머는 high watermark 를 넘어서 읽지 못합니다.
오프셋 4종 구분 — log-start-offset · committed offset · high watermark · LEO. 슬라이더로 팔로워 복제 진행과 컨슈머 커밋을 움직이면, high watermark가 ISR 내 최소 LEO로 결정되고 컨슈머가 그 이상을 읽을 수 없다는 점이 드러납니다.

복제 — 파티션 단위로 복사됩니다

내구성과 가용성은 복제(replication)로 확보합니다. 복제 단위는 토픽이 아니라 토픽-파티션입니다. 공식 문서는 프로덕션에서 흔히 쓰이는 설정으로 복제 계수(replication factor) 3을 예로 듭니다. 즉 같은 파티션의 사본이 항상 3개 존재합니다. 파티션마다 리더 하나와 팔로워 0개 이상이 있고, 쓰기는 리더로 갑니다.

이 장에서 나온 설정

Apache Kafka 4.3 공식 문서 기준 기본값. 브로커 설정과 토픽 설정을 구분해 표기했습니다.
설정 기본값 설명 튜닝 포인트
num.partitions
broker
1 자동 생성 토픽의 기본 파티션 수 소비 병렬성의 상한이 됩니다. 토픽을 명시 생성해 직접 지정하세요.
default.replication.factor
broker
1 자동 생성 토픽의 기본 복제 계수 1이면 브로커 한 대만 잃어도 데이터가 사라집니다.
auto.create.topics.enable
broker
true 존재하지 않는 토픽으로의 요청 시 자동 생성 오타 토픽이 조용히 만들어집니다. 운영 클러스터에서는 끄는 편이 안전합니다.
retention.ms
topic
604800000
(7일)
delete 정책에서 로그를 보관하는 최대 시간 재처리 여유 기간을 결정합니다. 삭제는 세그먼트 단위로 일어납니다(7장).
cleanup.policy
topic
delete delete 또는 compact (조합 가능) 상태 저장 토픽에 delete가 남아 있으면 데이터가 사라집니다(케이스 8).
message.max.bytes
broker
1048588 Kafka가 허용하는 최대 레코드 배치 크기(압축 후 기준) 토픽 레벨 max.message.bytes가 오버라이드합니다. 프로듀서·컨슈머 설정과 함께 맞춰야 합니다(케이스 10).

Kafka 생태계와 5개 API

Kafka는 서버(브로커)와 클라이언트가 TCP 기반 자체 프로토콜로 통신하는 분산 시스템입니다. 서버 일부는 저장 계층인 브로커를 이루고, 다른 일부는 Kafka Connect를 실행해 외부 시스템과 데이터를 주고받습니다. 공식 문서는 Java·Scala용 핵심 API를 다섯 개로 정리합니다.

Apache Kafka의 5개 핵심 API
API역할이 가이드의 담당 장
Admin API토픽·브로커 등 Kafka 객체 관리와 조회11장, CLI 치트시트
Producer API하나 이상의 토픽에 이벤트 스트림을 발행4장
Consumer API하나 이상의 토픽을 구독하고 이벤트를 처리5장
Kafka Streams API변환·집계·조인·윈도우·이벤트 시간 처리를 제공하는 스트림 처리 라이브러리10장
Kafka Connect API외부 시스템과의 재사용 가능한 import/export 커넥터9장

Schema Registry와 ksqlDB는 Apache Kafka 본체가 아니라 Confluent가 제공하는 별도 컴포넌트입니다. CCDAK 출제 범위에는 Schema Registry가 포함되므로 이 가이드도 8장에서 다룹니다.

Kafka 생태계 지도 — Apache Kafka 에 포함되는 컴포넌트와 별도 컴포넌트 가운데에 브로커로 이루어진 Kafka 클러스터가 있고 왼쪽에는 데이터를 쓰는 Producer API, Kafka Connect source 커넥터, MirrorMaker 2 가, 오른쪽에는 데이터를 읽는 Consumer API, Kafka Streams, Kafka Connect sink 커넥터가 있습니다. 이들은 모두 Apache Kafka 배포판에 포함되며 Admin API 와 kafka 로 시작하는 CLI 도구도 함께 들어 있습니다. 모든 데이터는 브로커의 로그를 거치고 클라이언트끼리 직접 주고받지 않습니다. 아래쪽 점선 영역의 Schema Registry, ksqlDB, REST Proxy 는 Apache Kafka 배포판에 없고 따로 설치하는 Confluent 계열 컴포넌트입니다. Kafka 생태계 지도 — 어디까지가 Apache Kafka 인가 Apache Kafka 프로젝트에 들어 있는 것 Kafka 클러스터 브로커 (KRaft 모드) 토픽 · 파티션 · 로그 컨트롤러 쿼럼 포함 Producer API 애플리케이션이 쓰기 Kafka Connect (source) 외부 시스템 → Kafka MirrorMaker 2 클러스터 간 복제 Consumer API 애플리케이션이 읽기 Kafka Streams Kafka → 처리 → Kafka Kafka Connect (sink) Kafka → 외부 시스템 Admin API · kafka-*.sh CLI 도구도 Apache Kafka 배포판에 포함됩니다. 데이터는 항상 브로커의 로그를 거칩니다 — 클라이언트끼리 직접 주고받지 않습니다. 따로 설치하는 컴포넌트 (Apache Kafka 배포판에 없음) Schema Registry 스키마 등록 · 호환성 검사 ksqlDB SQL 로 스트림 처리 REST Proxy HTTP 로 produce · consume 시험 주의: Schema Registry · ksqlDB · REST Proxy 는 Apache Kafka 기능이 아닙니다.
Kafka 생태계 지도 — 브로커 클러스터를 중심으로 Producer · Consumer · Connect · Streams · Schema Registry · ksqlDB가 어떻게 연결되는지

클라이언트는 어떻게 클러스터를 찾는가

클라이언트는 bootstrap.servers에 적힌 host:port 목록으로 최초 연결을 맺고, 그 연결로 메타데이터를 받아 클러스터 전체를 알아냅니다. 공식 문서는 이 목록에 전체 브로커를 적을 필요가 없다고 명시하면서도, 일부 서버가 죽어 있을 때를 대비해 여러 개를 적으라고 권고합니다.

부트스트랩 지점이 하나뿐입니다. 이 브로커가 재시작 중이면 클러스터가 정상인데도 클라이언트가 붙지 못합니다.

producer.properties
bootstrap.servers=kafka-1.internal:9092

초기 연결 지점을 이중화했습니다. 하나만 붙으면 나머지 브로커는 메타데이터로 알아내므로, 전체 목록을 적을 필요는 없습니다.

producer.properties
bootstrap.servers=kafka-1.internal:9092,kafka-2.internal:9092,kafka-3.internal:9092

Kafka 버전 표기 읽는 법 — 2.13은 Kafka 버전이 아닙니다

Kafka 배포 파일명은 두 개의 버전 번호를 한 줄에 담고 있어서 매우 흔하게 오해를 일으킵니다. Apache 아카이브의 4.3.1 디렉터리에는 kafka_2.13-4.3.1.tgz 하나만 올라와 있습니다.

배포 파일명 분해
kafka_2.13-4.3.1.tgz
      ────  ─────
      Scala  Kafka
      2.13   4.3.1
Kafka 배포 파일명 분해 — kafka_2.13-4.3.1.tgz 의 2.13 은 Scala 버전 배포 파일명 kafka_2.13-4.3.1.tgz 를 두 부분으로 분해합니다. 밑줄 뒤의 2.13 은 브로커를 컴파일한 Scala 버전이며 Kafka 4.x 는 Scala 2.13 배포판만 제공합니다. Scala 2.12 지원은 4.0 에서 제거되었습니다. 하이픈 뒤의 4.3.1 이 Apache Kafka 버전으로 major 4, minor 3, patch 1 이며 설정 기본값과 CLI, API 는 이 번호를 기준으로 봅니다. 아래 경고 상자는 Kafka 2.13 이라는 버전이 존재하지 않는다는 점을 알려 줍니다. Kafka 의 minor 버전은 2.8 다음이 3.0 이므로 2.9 부터 2.13 까지는 아예 없습니다. 맨 아래에는 2.6, 2.7, 2.8, 3.0 을 지나 3.9, 4.0, 4.3 으로 이어지는 실제 버전 흐름이 표시되어 있습니다. Kafka 버전 표기 읽는 법 — 2.13 은 Kafka 버전이 아닙니다 kafka _2.13 -4.3.1 .tgz 2.13 = Scala 버전 브로커를 컴파일한 Scala 의 버전입니다. Kafka 4.x 는 Scala 2.13 배포판만 제공합니다 (2.12 지원은 4.0 에서 제거). 4.3.1 = Apache Kafka 버전 major 4 · minor 3 · patch 1. 설정 기본값 · CLI · API 는 모두 이 번호를 기준으로 봅니다. Kafka 2.13 이라는 버전은 존재하지 않습니다. Kafka 의 minor 버전은 2.8 다음이 3.0 입니다 — 2.9 부터 2.13 까지는 아예 없습니다. 실제 Kafka 버전의 흐름 2.6 2.7 2.8 3.0 3.9 4.0 4.3 2.8 다음이 3.0 — 여기서 minor 번호가 건너뜁니다. Scala 버전(2.13)과는 아무 관계가 없습니다. Scala 를 직접 쓰지 않는다면 _2.13 배포판을 그대로 고르면 됩니다. 브로커 실행에는 Java 만 필요합니다.
버전 표기 분해 — kafka_2.13-4.3.0.tgz의 각 부분이 무엇을 의미하는지 지시선으로 분해
배포 파일명의 각 부분
표기의미
kafka_2.13Scala 2.13으로 컴파일된 배포판. 현행 Kafka가 제공하는 유일한 Scala 버전
-4.3.1Apache Kafka 버전
_2.12과거 배포판에 있던 Scala 2.12 빌드. 현행 Kafka에서는 제공되지 않습니다
kafka-4.3.1-src.tgz소스 배포판 (Scala 접두어가 없습니다)

내려받은 뒤 클러스터를 처음 띄우는 절차는 공식 quickstart와 같습니다. KRaft에서는 클러스터 UUID를 만들고 로그 디렉터리를 포맷한 뒤 브로커를 기동합니다. 동작하는 3노드 구성은 예제 1에서 다룹니다.

KRaft 단일 노드 부트스트랩 (공식 quickstart 기준)
tar -xzf kafka_2.13-4.3.1.tgz
cd kafka_2.13-4.3.1

# 1. 클러스터 UUID 생성
KAFKA_CLUSTER_ID="$(bin/kafka-storage.sh random-uuid)"

# 2. 로그 디렉터리 포맷 (KRaft 필수 단계)
bin/kafka-storage.sh format --standalone -t $KAFKA_CLUSTER_ID -c config/server.properties

# 3. 기동
bin/kafka-server-start.sh config/server.properties

# 4. 토픽 생성 — 항상 --bootstrap-server 를 씁니다
bin/kafka-topics.sh --create --topic quickstart-events --bootstrap-server localhost:9092
bin/kafka-topics.sh --describe --topic quickstart-events --bootstrap-server localhost:9092

대표 사용 사례 4가지

공식 문서가 드는 사례들을 이 가이드의 학습 경로와 묶어 정리했습니다.

대표 사용 사례와 관련 학습 지점
사례Kafka가 맡는 역할주의할 지점
결제·금융 트랜잭션 실시간 처리 주문/결제 이벤트를 순서 보장하며 여러 소비자에게 전달 중복 처리 방지가 필수. Kafka 내부 EOS와 외부 시스템 멱등성은 다른 문제입니다(6장)
IoT · 센서 데이터 수집 고빈도 측정값을 durable하게 수집하고 사후 재처리 허용 메시지 크기와 보관 용량 산정(7장)
데이터베이스 변경 캡처(CDC)와 통합 Connect로 DB 변경을 스트림화해 여러 목적지에 공급 source와 sink의 오프셋 저장 위치가 다릅니다(9장)
이벤트 기반 마이크로서비스 서비스 간 결합을 로그로 분리하고, 상태를 스트림으로 재구성 KStream과 KTable 중 무엇이 맞는 모델인지 판단(10장)

Kafka 4.x가 이전과 다른 점

이 가이드는 Apache Kafka 4.3.x를 기준으로 서술합니다. 시중 한국어 자료 대부분이 2.x/3.x(ZooKeeper 시대) 기준이므로, 특히 아래 세 가지는 예전 자료를 그대로 따라 하면 동작하지 않습니다.

흔한 오해

시험 포인트

확인 문제

네 가지 문항 유형(단일 선택 · 복수 선택 · 연결형 · 순서 배열)이 섞여 있습니다. 실제 CCDAK/CCAAK 시험에도 matching과 list order 유형이 출제되므로 함께 연습하세요. 키보드만으로 완주할 수 있습니다 — 숫자키로 선택, Enter로 제출입니다.

공식 문서 출처

이 장의 설정 기본값과 버전 사실은 모두 아래에서 확인했습니다 (Apache Kafka 4.3.1 문서 기준).