Kafka
Apache Kafka (아파치 카프카)
1. 개요
Apache Kafka는 고성능 분산 이벤트 스트리밍 플랫폼으로, 실시간 데이터 파이프라인 구축 및 스트림 분석을 위해 설계된 오픈소스 소프트웨어이다.
전통적인 메시지 큐(Message Queue, MQ)가 메시지의 전달과 소비 후 삭제라는 '전달' 중심의 역할에 집중했다면, Kafka는 데이터를 디스크에 순차적으로 저장하는 '로그(Log)' 기반의 저장소 역할을 겸한다. 이를 통해 데이터의 영속성을 보장하며, 동일한 데이터를 여러 소비자가 각자의 속도에 맞춰 반복해서 읽을 수 있는 발행-구독(Publish-Subscribe) 모델을 구현한다.
2. 핵심 아키텍처 및 동작 원리
Kafka는 클러스터 내의 여러 서버(Broker)에 데이터를 분산 저장하여 확장성과 안정성을 확보한다.
2.1 주요 구성 요소
- Producer: 데이터를 생성하여 Kafka 토픽으로 전송하는 애플리케이션이다.
- Consumer: 토픽에 저장된 데이터를 읽어와 처리하는 애플리케이션이다.
- Consumer Group: 여러 컨슈머가 하나의 그룹으로 묶여 토픽의 파티션을 분할 처리하는 논리적 단위이다. 이를 통해 데이터 처리량을 확장하고 부하를 분산한다.
- Broker: Kafka 서버 인스턴스를 의미하며, 데이터를 저장하고 Producer/Consumer의 요청을 처리한다.
- Topic: 데이터가 저장되는 논리적인 카테고리이다. (예:
user-login-logs,order-events) - Partition: 토픽을 물리적으로 나눈 단위이다. 하나의 토픽은 여러 개의 파티션으로 구성되어 병렬 처리를 가능하게 한다.
2.2 Topic, Partition 및 Offset
| 구분 | Topic (토픽) | Partition (파티션) | Offset (오프셋) |
|---|---|---|---|
| 정의 | 데이터의 논리적 그룹 (채널) | 토픽의 물리적 분할 단위 | 파티션 내 메시지의 고유 번호 |
| 역할 | 데이터 분류 및 식별 | 병렬 처리 및 부하 분산 | 데이터 읽기 위치 추적 및 기록 |
| 특징 | 하나 이상의 파티션을 포함함 | 메시지가 순차적으로 저장되는 Append-only 로그 | 0부터 시작하여 1씩 증가하는 정수 |
| 순서 보장 | 토픽 전체의 순서는 보장되지 않음 | 파티션 내부에서는 메시지 순서가 엄격히 보장됨 | 오프셋 순서대로 메시지가 소비됨 |
2.3 아키텍처 다이어그램
graph LR
subgraph Producers
P1[Producer 1]
P2[Producer 2]
end
subgraph Kafka_Cluster [Kafka Cluster]
subgraph Broker1 [Broker 1]
T1_P0[Topic A - Partition 0]
T1_P1[Topic A - Partition 1]
end
subgraph Broker2 [Broker 2]
T1_P0_R[Topic A - Partition 0 Replica]
T1_P2[Topic A - Partition 2]
end
end
subgraph Consumer_Group [Consumer Group]
C1[Consumer 1]
C2[Consumer 2]
end
P1 --> T1_P0
P2 --> T1_P1
T1_P0 --> C1
T1_P1 --> C1
T1_P2 --> C2
3. 주요 특징 및 장점
3.1 고가용성 및 복제 (Replication)
Kafka는 파티션을 여러 브로커에 복제하여 저장하는 Replication 기능을 제공한다. 특정 브로커에 장애가 발생하더라도 복제본(Replica)이 있는 다른 브로커가 리더(Leader) 역할을 승계하여 서비스 중단 없이 데이터를 제공한다.
3.2 높은 처리량 (Throughput)
- Sequential I/O: 무작위 접근(Random Access)이 아닌 디스크의 순차 쓰기 방식을 사용하여 디스크 I/O 성능을 극대화한다.
- Zero Copy: 커널 공간에서 유저 공간으로 데이터를 복사하지 않고 네트워크 카드로 직접 전송하는 Zero Copy 기술을 사용하여 CPU 사용량을 줄이고 전송 속도를 높인다.
3.3 확장성 (Scalability)
데이터 양이 증가하면 브로커를 추가(Scale-out)하고 파티션을 재분배함으로써 시스템 용량과 처리 능력을 선형적으로 확장할 수 있다.
4. Kafka 생태계 (Components)
Kafka는 단순한 메시지 브로커를 넘어 데이터 통합 및 처리를 위한 생태계를 제공한다.
- Kafka Connect: 외부 시스템(DB, 파일, S3 등)과 Kafka 사이의 데이터 이동을 자동화하는 프레임워크이다.
- Source Connector: 외부 시스템 → Kafka
- Sink Connector: Kafka → 외부 시스템
- Kafka Streams: Kafka 토픽의 데이터를 실시간으로 변환, 집계, 조인하는 가벼운 클라이언트 라이브러리이다. 별도의 클러스터 없이 애플리케이션 내에서 스트림 처리가 가능하다.
- ksqlDB: SQL 문법을 사용하여 Kafka 스트림 데이터를 실시간으로 쿼리하고 처리할 수 있게 해주는 스트리밍 데이터베이스이다.
5. 상세 설정 및 메커니즘
5.1 Zookeeper vs KRaft 모드
과거 Kafka는 클러스터 메타데이터 관리와 리더 선출을 위해 Apache Zookeeper에 의존했으나, 최근 KRaft(Kafka Raft) 모드가 도입되었다.
| 비교 항목 | Zookeeper 모드 | KRaft 모드 (ZooKeeper-less) |
|---|---|---|
| 관리 주체 | 외부 Zookeeper 앙상블 필요 | Kafka 브로커 내부에서 메타데이터 관리 |
| 복잡도 | 두 가지 서로 다른 시스템 운영 필요 | Kafka 단일 시스템으로 단순화 |
| 확장성 | Zookeeper의 성능이 병목 지점이 됨 | 수백만 개의 파티션까지 확장 가능 |
| 장애 복구 | Zookeeper-Broker 간 동기화 지연 발생 | 쿼럼(Quorum) 기반의 빠른 리더 선출 |
5.2 데이터 보존 정책 (Retention)
Kafka는 메시지를 무한히 저장하지 않고 설정된 정책에 따라 삭제한다.
* 시간 기반 보존 (log.retention.hours): 설정된 시간이 지난 데이터는 삭제한다. (기본값 168시간/7일)
* 크기 기반 보존 (log.retention.bytes): 파티션의 크기가 설정된 용량을 초과하면 오래된 데이터부터 삭제한다.
* 로그 압착 (Log Compaction): 동일한 키(Key)를 가진 메시지 중 최신 값만 남기고 나머지는 삭제하여 상태 정보를 유지하는 방식이다.
5.3 메시지 전달 보장 수준 (Acks)
Producer가 메시지를 보낼 때, 어느 정도의 확인 응답을 받을지 결정하여 신뢰성을 조절한다.
* acks=0: 응답을 기다리지 않는다. 처리 속도가 가장 빠르나 데이터 유실 가능성이 매우 높다.
* acks=1: 리더(Leader) 파티션에 저장되었다는 응답만 받는다. 리더 장애 시 복제본에 반영되지 않은 데이터는 유실될 수 있다.
* acks=all (또는 -1): 리더와 모든 ISR(In-Sync Replicas, 리더와 동기화된 복제본 그룹)에 저장되었음을 확인한다. 가장 안전하며 데이터 유실 가능성이 거의 없으나 지연 시간이 증가한다.
6. 실제 활용 사례 및 워크플로우
6.1 주요 활용 사례
- 로그 수집 파이프라인: 수많은 서버에서 발생하는 로그를 Kafka로 집결시킨 후, Elasticsearch나 Hadoop으로 전송하여 분석한다.
- 실시간 모니터링: 시스템 메트릭을 실시간으로 수집하여 임계치 초과 시 즉각적인 알림을 발생시킨다.
- 이벤트 기반 아키텍처 (EDA): 마이크로서비스(MSA) 간의 결합도를 낮추기 위해 서비스 간 통신을 비동기 이벤트 방식으로 처리한다.
6.2 구현 예시 (Python)
<a href="/doc/%EA%B8%B0%EC%88%A0/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/Python%20%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC/kafka-python" class="wiki-link wiki-link-missing">kafka-python</a> 라이브러리를 이용한 간단한 Producer와 Consumer 예제이다.
# Producer 예제
from kafka import KafkaProducer
# bootstrap_servers: 실제 운영 환경에서는 브로커 리스트(IP:Port)를 입력한다.
producer = KafkaProducer(bootstrap_servers=['localhost:9092'])
producer.send('my-topic', b'Hello Kafka!')
producer.flush()
# Consumer 예제
from kafka KafkaConsumer
# bootstrap_servers: 실제 운영 환경에서는 브로커 리스트(IP:Port)를 입력한다.
consumer = KafkaConsumer('my-topic', bootstrap_servers=['localhost:9092'],
auto_offset_reset='earliest', group_id='my-group')
for message in consumer:
print(f"Received: {message.value.decode('utf-8')}")
7. 운영 시 고려사항 및 최적화
7.1 파티션 개수 설정 전략
파티션은 한 번 늘리면 줄일 수 없으므로 신중하게 설정해야 한다.
* 처리량 계산: 필요한 전체 처리량 / 단일 컨슈머의 처리량 = 최소 파티션 수
* 주의사항: 파티션이 너무 많으면 파일 핸들러 증가 및 리밸런싱 시간이 길어져 성능이 저하될 수 있다.
7.2 Consumer Group과 리밸런싱 (Rebalancing)
Consumer Group 내의 컨슈머들은 파티션을 나누어 소비한다. 특정 컨슈머가 장애로 이탈하거나 새로운 컨슈머가 추가되면 파티션 소유권을 재배분하는 리밸런싱이 발생한다.
* 문제점: 리밸런싱 동안 해당 그룹의 모든 데이터 소비가 일시 중단되는 'Stop-the-world' 현상이 발생할 수 있다.
* 최적화: session.timeout.ms 및 heartbeat.interval.ms 설정을 통해 장애 감지 시간을 최적화하거나, 정적 멤버십(Static Membership)을 사용하여 불필요한 리밸런싱을 방지한다.
7.3 성능 튜닝 포인트
- Batch Size:
batch.size와linger.ms를 조절하여 메시지를 묶어서 전송함으로써 네트워크 오버헤드를 줄인다. - Compression:
compression.type(snappy, lz4, zstd 등)을 설정하여 네트워크 대역폭 사용량을 최적화한다.
이 문서는 AI 모델(gemma-4-31b)에 의해 생성된 콘텐츠입니다.
주의사항: AI가 생성한 내용은 부정확하거나 편향된 정보를 포함할 수 있습니다. 중요한 결정을 내리기 전에 반드시 신뢰할 수 있는 출처를 통해 정보를 확인하시기 바랍니다.