이 글은 카프카 핵심 가이드 책을 읽고 정리한 글입니다.
Prologue
‘카프카 핵심 가이드’ 책의 1장 ‘카프카 시작하기’를 읽고, 꼭 알아야 할 내용(핵심 위주)만 정리했다.
이 글에서는 카프카를 왜 사용해야 하는지(Why), 그리고 카프카를 구성하는 핵심 개념은 무엇인지에 초점을 맞췄다.
자세한 내용은 책의 1장을 참고하자.
카프카를 왜 사용하는가?
초기 시스템은 데이터를 보내는 애플리케이션(프로듀서)과 받아서 사용하는 애플리케이션(컨슈머)이 직접 연결된 단순한 구조로 시작한다.
하지만 비즈니스가 성장하고 시스템이 복잡해지면서, 데이터를 생산하는 프로듀서와 데이터를 필요로 하는 컨슈머의 수가 계속 늘어난다. 이때마다 시스템 간의 직접 연결(Point-to-Point)을 추가하면, 아래 그림과 같이 전체 아키텍처는 거미줄처럼 얽혀 추적하고 관리하기가 매우 어려워진다.
이러한 복잡성을 해결하기 위해 발행/구독(Publish/Subscribe) 모델을 사용한다. 모든 프로듀서는 데이터를 중앙 시스템으로 보내고, 모든 컨슈머는 이 중앙 시스템으로부터 데이터를 가져간다. 이 중앙 시스템이 바로 메시지 큐 또는 카프카와 같은 브로커다. 이를 통해 아래 그림처럼 프로듀서와 컨슈머 간의 직접적인 의존성이 제거되어 결합도가 낮아진다.
그러나 여기서 또 다른 문제가 발생할 수 있다. 모니터링 지표, 서버 로그, 사용자 클릭 정보 등 데이터의 종류에 따라 각각 별개의 메시징 시스템을 구축하는 것이다. 이는 결국 아래 그림과 같이 여러 개의 시스템을 중복으로 관리해야 하는 비효율을 초래한다.
카프카는 바로 이 문제를 해결하기 위해 등장했다.
중앙 집중형 발행/구독 시스템
(= 분산 스트리밍 플랫폼)으로서, 기존의 여러 발행/구독 시스템을 하나로 통합하고 대체하며
모든 종류의 데이터를 처리하는 데이터 허브(Data Hub) 역할을 수행한다.
결론적으로 카프카는 다음과 같은 강력한 특징 때문에 사용된다.
-
다수의 프로듀서와 다수의 컨슈머: 여러 시스템이 동시에 데이터를 보내고, 여러 시스템이 간섭 없이 각자 필요한 데이터를 소비할 수 있다.
-
디스크 기반 데이터 보존: 데이터를
디스크
에 안전하게 보존하므로, 컨슈머가 일시적으로 중단되거나 느려져도 데이터 유실 없이 나중에 처리할 수 있다. -
확장성과 고성능: 데이터양이 급증하더라도 브로커를 추가하는 방식으로 손쉽게 수평 확장이 가능하며, 높은 처리량과 낮은 지연 시간을 보장한다.
카프카 핵심 개념
메시지 (Message)
-
카프카에서 다루는 데이터의 기본 단위다.
-
단순한 바이트 배열 로, 특정 형식이나 의미를 갖지 않는다.
-
메시지는 키(Key)와 밸류(Value) 로 구성된다.
-
키는 메시지를 어느 파티션에 저장할지 결정하는 데 사용된다.
스키마 (Schema)
-
메시지의 구조를 정의하는 형식이다. 카프카 자체는 메시지를 바이트 배열로만 보지만, 데이터를 올바르게 해석하기 위해 스키마를 사용하는 것을 권장한다.
-
프로듀서와 컨슈머가 스키마를 통해 데이터를 일관된 형식으로 주고받을 수 있어 서로 독립적으로 개발 및 변경이 가능하다. (e.g. JSON, Avro)
-
이를 통해 프로듀서와 컨슈머의 결합을 더욱 낮추는 핵심적인 역할을 한다
토픽 (Topic)과 파티션 (Partition)
-
메시지를 구분하는 카테고리를
토픽
이라고 한다. 데이터베이스의 테이블이나 파일 시스템의 폴더와 유사하다. -
토픽은 하나 이상의 파티션으로 나뉜다. 파티션은 하나의 로그 파일과 같다.
-
메시지는 파티션에 추가(append-only) 방식으로 저장된다.
-
메시지의 순서는 단일 파티션 내 에서만 보장된다. 토픽 전체에 대한 순서는 보장되지 않는다.
-
파티션을 통해 데이터를 분산 저장하여 확장성과 가용성을 높인다. (아래 그림 참고)
프로듀서 (Producer)와 컨슈머 (Consumer)
-
프로듀서
는 새로운 메시지를 생성하여 특정 토픽으로 보내는 역할을 한다. -
컨슈머
는 특정 토픽에서 메시지를 읽어오는 역할을 한다. -
컨슈머는
컨슈머 그룹(Consumer Group)
에 속해서 동작한다. -
아래 그림과 같이, 하나의 파티션은 컨슈머 그룹 내에서 오직 하나의 컨슈머에 의해서만 소비된다. 이를 통해 메시지 처리를 병렬로 수행할 수 있다.
-
동일 그룹 내 (병렬 처리): 그림을 보면 각 파티션(
0
,1
,2
,3
)이 그룹 내의 단 한 개의 컨슈머에게만 할당된 것을 확인할 수 있다. 예를 들어 파티션 0은 컨슈머 0이, 파티션 3은 컨슈머 2가 전담하여 처리한다. 이를 통해 그룹 내에서 메시지 처리 순서를 보장하고 중복 소비를 방지한다. -
컨슈머와 파티션의 관계: 컨슈머의 수가 파티션의 수보다 적기 때문에, 컨슈머 1은 파티션 1과 파티션 2를 모두 담당하게 되었다. 이처럼 하나의 컨슈머는 여러 파티션을 처리할 수 있지만, 반대는 불가능하다.
-
다른 그룹 간 (독립적 구독): 만약 이 그림의 토픽을 구독하는 새로운 컨슈머 그룹 B가 생긴다면, 그 그룹 역시 현재 그룹과는 완전히 독립적으로 파티션 0, 1, 2, 3의 모든 메시지를 처음부터 소비하게 된다. 각 그룹은 자신만의 오프셋(offset, 어디까지 읽었는지의 위치)을 관리하기 때문이다.
-
-
이러한 구조 덕분에 하나의 토픽 데이터를 가지고, 한쪽에서는 실시간 분석(그룹 A)을, 다른 한쪽에서는 데이터베이스 저장(그룹 B)을 하는 등 다양한 목적의 애플리케이션을 동시에 운영할 수 있다.
브로커 (Broker)와 클러스터 (Cluster)
-
카프카 서버 하나를
브로커
라고 부른다. -
브로커는 프로듀서로부터 메시지를 받아 저장하고, 컨슈머의 요청에 따라 메시지를 전달한다.
-
여러 브로커가 모여 하나의 클러스터 를 구성하며, 클러스터 내의 브로커 중 하나는 컨트롤러(Controller) 역할 을 맡아 다른 브로커들을 관리한다.
-
아래 그림은 카프카의 고가용성과 내구성을 보장하는 핵심 기능인 복제(Replication) 동작 방식을 보여준다.
-
각 파티션은 여러 브로커에 복제본을 가질 수 있는데, 이 중 단 하나만
리더
(Leader) 역할을 하고 나머지는팔로워
(Follower) 가 된다. 모든 데이터의 읽고 쓰는 작업은리더
를 통해서만 처리되는 것이 원칙이다.-
그림에서 ‘토픽 A, 파티션 0’의 리더는 ‘브로커 1’이다. 프로듀서가 보낸 메시지는 먼저 리더인 ‘브로커 1’에 기록된 후, ‘A/0 복제’ 흐름을 따라 ‘브로커 2’에 있는 팔로워에게 복사된다. 반대로 ‘토픽 A, 파티션 1’의 리더는 ‘브로커 2’이며, 같은 방식으로 ‘브로커 1’의 팔로워에게 메시지가 복제된다.
-
이러한 구조 덕분에 리더 역할을 하던 브로커(예: 브로커 1)에 장애가 발생하더라도, 다른 브로커에 있던 팔로워(브로커 2의 파티션 0)가 즉시 새로운 리더로 승격된다. 이를 통해 카프카는 데이터 유실 없이 중단 없는 서비스를 이어갈 수 있다.
-
오프셋 (Offset)
-
파티션에 저장된 각 메시지의 고유한 순번을 나타내는 정수 값이다.
-
컨슈머는 자신이 어디까지 메시지를 읽었는지
오프셋
을 통해 기록 한다. -
이를 통해 컨슈머에 장애가 발생했다가 복구되어도 마지막으로 읽은 위치부터 다시 작업을 이어갈 수 있다.
보존 (Retention)
-
카프카가 메시지를 얼마나 오랫동안 디스크에 보관할지를 정하는 정책이다.
-
메시지를 특정 시간(예: 7일) 또는 파티션의 크기(예: 1GB) 기준으로 보존할 수 있다.
-
이 보존 정책 덕분에 컨슈머가 실시간으로 동작하지 않아도 데이터가 유실되지 않으며, 필요할 때 언제든 과거의 데이터를 소비할 수 있다. 이는 카프카의 핵심적인 내구성(durability) 기능이다.