Event Streaming & Kafka Dynamics
방대한 양의 실시간 데이터를 순차적으로 기록하고 분산 처리하는 이벤트 스트리밍 시스템의 내부 물리 구조와 아파치 카프카의 파티셔닝 및 복제 메커니즘을 다루는 학습 노드입니다.
Article
M
Me
hyunyoun's Blog
network-communicationnetworkcommunicationdistributed-messagingevent-streamingkafka-dynamicslearningkafka11 min read
1. Overview
이벤트 스트리밍과 카프카 역학(Event Streaming & Kafka Dynamics)은 메시지를 큐에 담아 전달하고 지워버리던 우체부(RabbitMQ)의 시대를 끝내고, 모든 트래픽을 거대한 불변의 디스크 파일(Log)에 순서대로 새겨버리는 미친 처리량(Throughput)의 데이터 댐, Kafka의 물리적 구조를 해부합니다.
학습자는 메시지 브로커가 느려지는 주범이었던 RAM 의존성을 버리고, 오히려 가장 느리다고 여겨졌던 하드디스크(HDD)의 순차 쓰기(Sequential I/O)를 활용해 RAM보다 빠른 속도를 뽑아내는 디스크 기반 스트리밍의 역설을 뜯어봅니다. 나아가 디스크에서 네트워크로 데이터를 복사할 때 CPU를 싹 다 건너뛰고 커널 레벨에서 다이렉트로 쏴버리는 **제로 카피(Zero-Copy)**의 네트워크 가속 마법을 장악합니다. 마지막으로, 수십 대의 컨슈머가 엉키지 않고 데이터를 나누어 먹기 위해 도입된 **파티셔닝(Partitioning)과 컨슈머 그룹(Consumer Group)**의 수평 확장 역량을 확보합니다.
2. Scope & Boundaries
In-Scope
- Log-Structured Storage: 파일 끝에만 데이터를 이어 붙이는(Append-only) 순차 I/O의 물리적 성능.
- Zero-Copy Network:
sendfile()시스템 콜을 이용한 OS 커널 단위의 컨텍스트 스위칭 생략. - Partitions & Consumer Groups: 1개의 토픽을 여러 파티션으로 쪼개고, 컨슈머 그룹 내 멤버들이 이를 할당받아 병렬(Parallel) 처리하는 네트워크/디스크 분산 구조.
- Offset Tracking: 브로커가 "누가 어디까지 읽었나"를 기억하지 않고, 컨슈머 스스로가 자신의 오프셋(Offset)을 기록하는 Pull 모델의 패러다임.
Out-of-Scope
- Kafka Streams / ksqlDB: 실시간 스트림 데이터를 가공하고 집계(Join, Windowing)하는 애플리케이션 레벨의 스트림 프로세싱 데이터 엔지니어링 / 파이프라인 영역으로 분리.
- Zookeeper / KRaft: 카프카 클러스터 노드 간의 리더 선출 및 합의 알고리즘 07-04-03 Consensus & Raft 분산 시스템 영역으로 위임.
Boundaries
- Message Queue (RabbitMQ) vs Event Stream (Kafka): RabbitMQ는 편지입니다. A가 읽으면 편지는 큐(메모리)에서 '삭제(Pop)'됩니다. B는 그 편지를 다시 읽을 수 없습니다. 반면 Kafka는 '도서관의 역사책'입니다. A가 1페이지부터 10페이지까지 읽고(Pull), 자기 수첩에 "나 10페이지까지 읽음(Offset)"이라고 적어둡니다. 책은 절대 삭제되지 않습니다. B가 와서 1페이지부터 100페이지까지 또 읽을 수 있습니다. 데이터의 '휘발(Queue)'과 '영속(Stream Log)'이라는 인프라적 태생의 차이를 명확히 경계 짓습니다.
3. Counterexample
- 랜덤 I/O와 파티션 폭주 (Disk Thrashing): 카프카 클러스터에 토픽(Topic)을 만들며 초보 관리자가 수평 확장을 맹신하여 파티션을 10,000개로 쪼개버렸습니다. 카프카의 본질은 파티션 1개당 디스크 파일 1개에 '순차 쓰기(Sequential I/O)'를 하여 속도를 내는 것입니다. 파일이 10,000개가 되자, 디스크 헤드가 10,000개의 파일 끝을 이리저리 미친 듯이 옮겨 다니며 기록해야 하는 끔찍한 '랜덤 쓰기(Random I/O)'로 물리적 변질이 일어납니다. 카프카의 디스크 처리 속도가 수백 배 나락으로 떨어진 물리 법칙(Physics) 무지의 결과입니다.
- 컨슈머 초과 배치 (Idle Consumers): 토픽의 파티션을 딱 3개로 만들어 놨는데, 데이터가 밀린다며 개발팀이 컨슈머(Consumer) 서버를 5대로 늘렸습니다(스케일 아웃). 카프카의 철칙 상 "1개의 파티션은 같은 컨슈머 그룹 내의 딱 1대 컨슈머에게만 할당"됩니다. 결국 파티션 3개에 컨슈머 3대만 연결되어 일하고, 새로 투입된 비싼 EC2 컨슈머 2대는 파티션을 할당받지 못한 채 아무 일도 하지 않고 영원히 놀고먹게(Idle) 됩니다. 네트워크 파티셔닝의 할당 공식을 무시한 자본 낭비입니다.
4. Prerequisites
- 디스크 I/O (Basic): Sequential Access(순차) vs Random Access(랜덤)의 속도 차이. (04-04-02 File Systems)
- Push vs Pull (Basic): 메시지 큐의 폴링 패러다임. (08-05-01 Message Queues)
5. Learning Map
6. Learning Topics
Basic
Core Topic 01: 역설적 속도, 디스크 순차 쓰기 (Log-Structured Storage)
- Why to Learn: 메시징 브로커는 인메모리(RAM)여야만 빠르다는 고정관념을 박살 내고, 값싸고 방대한 디스크(HDD)를 활용해 초당 기가바이트를 삼키는 불변 로그 아키텍처를 통찰하기 위함입니다.
- What to Learn:
- Concepts: Append-only Log, Sequential I/O vs Random I/O, Page Cache, Immutable Data.
- Skills: 전통적 DB의 랜덤 B-Tree 업데이트 속도와, 카프카의 단순 Append-only 로깅 속도를 디스크 헤더의 물리적 움직임 관점에서 비교 분석하기.
- How to Learn:
- 1단계: 인메모리 큐의 한계: RabbitMQ는 메시지를 받으면 RAM에 올립니다. RAM이 꽉 차면 억지로 디스크로 내립니다(Swap). 이 과정에서 엄청난 성능 저하가 생깁니다.
- 2단계: 하드디스크의 재발견: 카프카는 RAM을 무시하고 받은 메시지를 무조건 디스크(하드)에 씁니다. "디스크는 느리잖아?" 아닙니다. 카프카는 디스크의 '끝(Tail)'에만 데이터를 무식하게 이어 붙입니다(Append-only 순차 쓰기). 디스크 헤더가 물리적으로 윙~ 하고 움직일(Random I/O) 필요 없이 한 곳에서 쭉 쓰기만 하므로, 놀랍게도 이 '디스크 순차 쓰기' 속도는 'RAM 랜덤 쓰기' 속도를 능가하는 물리적 역설을 해부합니다. 게다가 리눅스 커널의 남는 RAM 잉여 공간(Page Cache)까지 영악하게 다 끌어다 씁니다.
- Implement: 순차 vs 랜덤 디스크 I/O 벤치마크 모사(Python pseudo).
Random Write (DB Update): 파일의 10번째 줄, 50번째 줄을 찾아다니며 수정. 디스크 Seek Time 때문에 초당50MB/s기록.Sequential Write (Kafka): 그냥 파일의 제일 끝을 열고write()만 죽어라 호출. 디스크 Seek가 0이므로 초당500MB/s통과. 디스크의 물리적 약점을 완전히 피해 가는 로그 구조의 힘 렌더링.
Recommended
Core Topic 02: CPU를 건너뛰어라, 제로 카피 (The Magic of Zero-Copy)
- Why to Learn: 수십 기가바이트의 데이터를 디스크에서 퍼서 네트워크로 쏠 때 발생하는 어마어마한 CPU 오버헤드와 RAM 복사 비용을 완전히 증발시켜 버리는 리눅스 OS 레벨의 네트워크 가속술을 장악하기 위함입니다.
- What to Learn:
- Concepts: Zero-Copy,
sendfile()System Call, Context Switch (User space vs Kernel space), Network Interface Card (NIC) DMA. - Skills: 일반적인 파일 읽어서 네트워크로 쏘는(4번의 데이터 복사) 과정과 제로 카피(2번의 데이터 복사) 파이프라인의 시스템 콜 호출 스택 도해.
- Concepts: Zero-Copy,
- How to Learn:
- 1단계: 구식 데이터 복사 (4-Copy): 컨슈머가 "데이터 줘"라고 하면 서버는 1. 디스크에서 커널(RAM)로 복사 2. 커널에서 카프카 앱(유저 RAM)으로 복사 3. 카프카 앱에서 다시 커널 소켓(RAM)으로 복사 4. 소켓에서 랜카드(NIC)로 복사하여 쏩니다. 이 짓을 할 때마다 커널과 유저 모드를 넘나드는 컨텍스트 스위칭(Context Switch)이 발생해 CPU가 피를 토합니다.
- 2단계: 제로 카피의 축지법: 카프카는 데이터를 수정할 필요가 없으므로 유저(카프카 앱) 영역으로 데이터를 끌고 올라올 필요조차 없습니다. OS에게
sendfile()명령 하나만 내립니다. "커널아, 디스크에 있는 저 데이터 바로 랜카드로 쏴버려." 디스크 커널 랜카드로 카프카 앱(CPU)을 싹 다 건너뛰고 다이렉트로 복사(Zero-Copy)되어 미친듯한 네트워크 처리량(Throughput)을 뽑아내는 마법을 뜯어봅니다.
- Implement: Zero-Copy CPU 부하 프로파일링 모사.
파일 크기
10GB.Standard Mode (read+send): User/Kernel 모드 전환 4회 반복.CPU 80% 사용, 소요 시간10초.Zero-Copy Mode (sendfile): 커널 내부 DMA 통로 직결.CPU 5% 사용 (앱은 구경만 함), 소요 시간2초. L7 앱(카프카)이 커널 레벨의 I/O 파이프를 영악하게 뚫어낸 인프라 최적화 애니메이션.
Practical
Core Topic 03: 고속도로 차선 늘리기, 파티셔닝 (Partitions & Parallelism)
- Why to Learn: 1대의 브로커 서버가 처리할 수 있는 물리적 디스크/네트워크 한계를 넘어서기 위해, 거대한 데이터의 강줄기(Topic)를 쪼개어 수십 대의 서버에 나누어 담는 수평 분산의 핵심을 쥐기 위함입니다.
- What to Learn:
- Concepts: Topic (논리적 묶음), Partition (물리적 분할), Sharding, Horizontal Scaling, Partition Key (메시지 라우팅).
- Skills: 토픽에 파티션이 3개 있을 때, 키(Key)가 없는 메시지는 라운드 로빈(Round Robin)으로 분산되고 키(User ID)가 있는 메시지는 해싱되어 특정 파티션으로 꽂히는 라우팅 규칙 설계.
- How to Learn:
- 1단계: 단일 병목 (1 Topic, 1 Partition): '주문로그'라는 토픽(폴더)이 1개 있습니다. 데이터가 1초에 100만 건 들어옵니다. 하드디스크 1개의 쓰기 속도를 초과하여 서버가 뻗습니다.
- 2단계: 쪼개서 분산하라 (Partitions): '주문로그' 토픽을 물리적으로 3개의 차선(Partition 0, 1, 2)으로 쪼갭니다. 100만 건이 들어오면 차선별로 33만 건씩 나뉘어 3대의 다른 하드디스크(브로커 3대)에 분산 저장됩니다(수평 확장). 단, 순서가 중요한 데이터("1번 유저의 가입 결제")는 파티션이 나뉘면 순서가 꼬이므로, 'User ID'를 열쇠(Partition Key)로 달아 던지면 무조건 똑같은 차선(예: Partition 1)으로 배정되어 그 안에서만의 순서를 완벽히 보장하는 분산과 순서의 트레이드오프를 해부합니다.
- Implement: 파티셔닝 라우터(Partitioner) 로직.
Topic: Orders, Partitions: 3. 메시지 1:Key=null, Data="A". 해시 키가 없으므로Partition 0(라운드 로빈). 메시지 2:Key=null, Data="B".Partition 1. 메시지 3:Key="User55", Data="가입".hash("User55") % 3 = Partition 2. 메시지 4:Key="User55", Data="결제". 역시hash("User55") % 3 = Partition 2.User55의 두 메시지가 무조건 같은 파티션(차선)으로 꽂혀서 순서 역전이 방지되는 큐잉 렌더링.
Advanced
Core Topic 04: 나눠 먹기의 기술, 컨슈머 그룹 (Consumer Groups & Offsets)
- Why to Learn: 쏟아지는 초당 100만 건의 트래픽을 컨슈머 서버 1대가 처리할 수 없기에, 여러 대의 컨슈머가 똑같은 파티션 데이터를 중복해서 먹지 않게 철저히 구역을 나누어주는 병렬 처리 생태계를 장악하기 위함입니다.
- What to Learn:
- Concepts: Consumer Group (컨슈머 그룹), Offset (오프셋/책갈피), Partition Assignment (할당 룰), Rebalancing (리밸런싱).
- Skills: "파티션 4개, 컨슈머 3대"일 때의 분배 상태를 추적하고, 컨슈머 1대가 죽었을 때 남은 2대가 4개의 파티션을 재분배(Rebalancing)받는 고가용성 네트워크 이동 도해.
- How to Learn:
- 1단계: 오프셋 책갈피: 기존 큐는 줬으면(Pop) 삭제합니다. 카프카는 냅둡니다(로그 불변성). 대신 컨슈머가 "나 파티션 0번의 50번째(Offset 50) 줄까지 읽었음!"이라고 카프카 칠판에 책갈피를 적어놓습니다. 죽었다 깨어나도 51번째 줄부터 다시 읽어갑니다. 브로커의 뇌를 가볍게(Dumb Broker, Smart Consumer) 만든 혁명입니다.
- 2단계: 컨슈머 그룹의 할당: 파티션이 3개(P0, P1, P2)입니다. 처리 서버(컨슈머)를 3대 띄우고 같은 '컨슈머 그룹 A'로 묶습니다. 카프카는 3대에게 각각 P0, P1, P2를 1<1로>1로> 칼같이 나눠줍니다. 서로 절대 남의 구역을 침범하지 않아 중복 처리가 안 됩니다.
- 3단계: 초과 배치의 멍청함 (Idle): 만약 서버를 4대로 띄우면? P0, P1, P2를 3대가 나눠 먹고, 남은 4번째 서버는 영원히 손가락만 빱니다(Idle). 파티션 개수가 컨슈머 병렬성의 '물리적 최댓값'이 되는 카프카 스케일링의 절대 공식을 뜯어봅니다.
- Implement: 리밸런싱(Rebalancing) 폭풍 시뮬레이터.
Topic Partitions: 0, 1, 2, 3.Group A: Consumer 1(P0, P1), Consumer 2(P2, P3). 장애 발생:Consumer 2서버 전원 나감(Ping 타임아웃).Broker(Group Coordinator)가 장애 인지[REBALANCING TRIGGERED].Consumer 1에게 잠시 작업 멈추라(Stop the world) 지시 후 4개의 파티션을 전부 몰빵함Consumer 1(P0, P1, P2, P3)로 독박 쓰며 처리가 속개되는 페일오버(Failover) 매트릭스 렌더링.
7. Terminology
8. References
Primary
- [P1] CS2023 - Software Engineering (SE) - Distributed System Architectures (Stream Processing)
- [P5] SFIA - System Software (SYSP) - Message Brokers and Event Streaming
Secondary
- [Designing Data-Intensive Applications] Martin Kleppmann - Log-based Message Brokers
- [Kafka: The Definitive Guide] Neha Narkhede - Internal Architecture (Zero-Copy, Partitions, Consumer Groups)
Industry
- [Apache Kafka Documentation] - Design (File system, Pagecache, Zero-copy)
- [Confluent Blog] - How Kafka's Storage Internals Work
9. Final Checklist
Primary
- 메시지를 메모리(RAM)에 저장했다 지우는 전통적 Message Queue 방식과 달리, 파일 끝에 불변의 로그로 이어 붙이는(Append-only Sequential I/O) 방식을 통해 디스크 성능 한계를 돌파한 카프카의 물리적 아키텍처를 설명할 수 있는가?
- OS 커널 영역에서 랜카드 버퍼로 직접 데이터를 넘기는
sendfile()시스템 콜 기반의 제로 카피(Zero-Copy)가, 컨텍스트 스위칭과 CPU 오버헤드를 극적으로 줄여주는 네트워크 전송 파이프라인을 증명할 수 있는가?
Secondary
- 단일 토픽에 초당 100만 건의 메시지가 몰릴 때, 이를 여러 개의 파티션(Partition)으로 분할하여 다수의 브로커 디스크에 분산시키고 수평 확장(Scale-out)하는 데이터 샤딩(Sharding) 메커니즘을 해부할 수 있는가?
- 메시지에 파티션 키(Partition Key, 예: User ID)를 지정했을 때, 라운드 로빈(Round Robin) 분산 방식을 무시하고 해싱(Hashing)에 의해 무조건 동일한 파티션에 배정되어 해당 유저 이벤트의 완벽한 순서 보장을 이루는 방어 로직을 평가할 수 있는가?
Industry
- 컨슈머 그룹(Consumer Group) 내에서 파티션과 컨슈머는
N : 1로만 할당된다는 제약 조건을 인지하고, 파티션 개수(3개)보다 컨슈머(4대)를 더 늘렸을 때 발생하는 잉여 인스턴스(Idle) 자원 낭비의 근본 원인을 논증할 수 있는가? - 기존 컨슈머 1대가 죽었을 때, 브로커 코디네이터가 이를 감지하고 살아남은 컨슈머들에게 죽은 서버가 맡았던 파티션을 재분배하는 리밸런싱(Rebalancing) 과정의 'Stop the World' 단기 지연 현상을 식별할 수 있는가?