반응형
Apache Kafka 완벽 가이드 - 개념부터 실전 사례까지
현대의 디지털 환경에서 데이터는 기하급수적으로 증가하고 있습니다. 특히 대용량 실시간 데이터 처리가 중요해지면서, 기업들은 효율적인 데이터 스트리밍 플랫폼을 찾고 있습니다.
Netflix는 하루 5000억 건의 이벤트를 처리하고, LinkedIn은 하루 1조 개의 메시지를 실시간으로 전송하며, Uber는 수백만 건의 위치 정보를 실시간으로 처리합니다. 이 모든 것을 가능하게 하는 핵심 기술이 바로 Apache Kafka입니다.
Apache Kafka는 LinkedIn에서 개발하여 2011년 오픈소스로 공개된 분산 이벤트 스트리밍 플랫폼으로, 현재 전 세계 80% 이상의 Fortune 100 기업에서 사용하고 있습니다. 대용량의 실시간 데이터를 빠르고 안정적으로 처리할 수 있도록 설계된 메시지 시스템입니다.
이 글에서는 Kafka의 기본 개념부터 핵심 구성 요소, 실제 사용법, 그리고 Netflix와 Uber 같은 글로벌 기업들의 실전 사례까지 완벽하게 정리하여 Kafka를 처음 접하는 분들도 쉽게 이해하고 활용할 수 있도록 도와드리겠습니다. 끝까지 읽어보시기 바랍니다.
목차
1. Kafka의 기본 개념과 핵심 구성 요소
2. Kafka의 동작 원리와 주요 특징
3. Kafka 설치 및 실전 사용법
4. 글로벌 기업의 Kafka 실전 사례
5. 자주 묻는 질문 (FAQ)
#1. Kafka의 기본 개념과 핵심 구성 요소
Apache Kafka는 LinkedIn에서 2010년경 급격한 성장으로 인한 데이터 처리 문제를 해결하기 위해 개발했습니다. 기존 메시징 시스템으로는 낮은 처리량, 확장성 부족, 데이터 손실 위험, 복잡한 아키텍처 문제를 해결할 수 없었기 때문입니다.
1) Kafka의 핵심 목표
Kafka는 세 가지 핵심 목표를 달성하기 위해 설계되었습니다.
① 높은 처리량 (High Throughput) - 초당 수백만 건의 메시지를 처리합니다.
② 확장성 (Scalability) - 클러스터에 브로커를 추가하여 수평 확장이 가능합니다.
③ 내구성 (Durability) - 디스크에 메시지를 저장하여 데이터 손실을 방지합니다.
. . . . .
2) 이벤트 스트리밍과 메시지 큐의 차이
이벤트 스트리밍은 실시간으로 발생하는 이벤트(데이터)를 지속적으로 캡처하고, 저장하고, 처리하고, 전달하는 것을 의미합니다. 온라인 쇼핑몰의 클릭 이벤트 추적, 배달 앱의 실시간 위치 정보 전송, 금융 시스템의 거래 데이터 실시간 처리, IoT 센서 데이터 스트리밍 등이 대표적인 예입니다.
| 구분 | 전통적인 메시지 큐 | Kafka (이벤트 스트리밍) |
|---|---|---|
| 메시지 보관 | 한 번 소비하면 큐에서 제거 | 일정 기간 동안 디스크에 보관 |
| 다중 소비 | 여러 소비자가 같은 메시지 읽기 불가 | 여러 소비자가 독립적으로 읽기 가능 |
| 재처리 | 메시지 재처리 어려움 | 과거 데이터 재처리 가능 |
. . . . .
3) Kafka의 핵심 구성 요소
(1) Producer (프로듀서)
Producer는 Kafka에 메시지(이벤트)를 발행(전송)하는 애플리케이션입니다.
① 애플리케이션에서 발생한 이벤트를 Kafka Topic으로 전송
② 메시지를 어떤 파티션으로 보낼지 결정 (파티셔닝)
③ 메시지의 직렬화(Serialization) 수행
④ 배치 처리를 통한 효율적인 전송
// Java Producer 예제
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
Producer<String, String> producer = new KafkaProducer<>(props);
// 메시지 전송
ProducerRecord<String, String> record =
new ProducerRecord<>("user-events", "user123", "login");
producer.send(record);
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
Producer<String, String> producer = new KafkaProducer<>(props);
// 메시지 전송
ProducerRecord<String, String> record =
new ProducerRecord<>("user-events", "user123", "login");
producer.send(record);
(2) Consumer (컨슈머)
Consumer는 Kafka Topic에서 메시지를 읽어오는(소비하는) 애플리케이션입니다.
① 특정 Topic의 메시지를 구독하고 읽어옴
② 읽은 위치(Offset)를 관리하여 메시지 추적
③ 메시지의 역직렬화(Deserialization) 수행
④ Consumer Group을 통한 병렬 처리
Consumer Group의 핵심 원칙: 하나의 파티션은 Consumer Group 내에서 오직 하나의 Consumer만 읽을 수 있습니다. 이를 통해 메시지 순서를 보장하면서도 병렬 처리가 가능합니다.
(3) Topic과 Partition
Topic은 메시지가 저장되는 논리적인 공간으로, 데이터베이스의 테이블과 유사한 개념입니다. 메시지를 카테고리별로 분류하는 단위이며, 하나 이상의 파티션으로 구성됩니다. 예를 들어 "user-events", "payment-logs", "sensor-data" 같은 이름을 가집니다.
Partition은 Topic을 물리적으로 나눈 단위로, Kafka의 병렬 처리와 확장성의 핵심입니다.
① 각 파티션은 순서가 보장되는 불변의 메시지 시퀀스입니다.
② 파티션 내에서는 메시지 순서가 보장됩니다.
③ 각 메시지는 Offset이라는 고유한 번호를 가집니다.
④ 파티션은 서로 다른 브로커에 분산 저장됩니다.
Topic: user-events (3개의 파티션)
Partition 0: [msg0, msg3, msg6, msg9, ...]
Partition 1: [msg1, msg4, msg7, msg10, ...]
Partition 2: [msg2, msg5, msg8, msg11, ...]
각 파티션은 독립적으로 처리되어 병렬성 향상
Partition 0: [msg0, msg3, msg6, msg9, ...]
Partition 1: [msg1, msg4, msg7, msg10, ...]
Partition 2: [msg2, msg5, msg8, msg11, ...]
각 파티션은 독립적으로 처리되어 병렬성 향상
(4) Broker와 Zookeeper
Broker는 Kafka 서버를 의미하며, 메시지를 저장하고 Consumer에게 전달하는 역할을 합니다. Topic의 파티션 데이터를 디스크에 저장하고, Producer로부터 메시지를 수신하며, Consumer에게 메시지를 전달하고, 파티션의 리더(Leader) 또는 팔로워(Follower) 역할을 수행합니다.
Zookeeper는 Kafka 클러스터의 메타데이터를 관리하고 브로커 간의 조율을 담당합니다. 브로커 목록 및 상태 관리, Topic 설정 정보 저장, 파티션 리더 선출, Consumer Group 관리 등의 역할을 수행합니다. 참고로 Kafka 3.x부터는 Zookeeper 없이 동작 가능합니다.
#2. Kafka의 동작 원리와 주요 특징
Kafka가 어떻게 메시지를 처리하고, 왜 이렇게 빠르고 안정적인지 동작 원리와 주요 특징을 알아보겠습니다.
1) 메시지 발행 (Produce)과 소비 (Consume) 과정
(1) 메시지 발행 단계
① 메시지 생성 - Producer가 메시지 생성
② 직렬화 - 메시지를 바이트 배열로 변환
③ 파티셔닝 - 메시지가 저장될 파티션 결정 (키가 있으면 키의 해시값으로, 없으면 라운드 로빈 방식)
④ 배치 처리 - 여러 메시지를 모아서 한 번에 전송하여 효율성 향상
⑤ 전송 및 복제 - 파티션 리더 브로커로 메시지 전송 후 팔로워 브로커에 복제
⑥ ACK 응답 - 저장 완료 후 Producer에게 응답
(2) 메시지 소비 단계
① Consumer가 Topic을 구독
② Consumer Group 내에서 파티션 분배
③ 마지막으로 읽은 위치(Offset) 확인
④ 파티션에서 메시지 가져오기 (Fetch)
⑤ 바이트 배열을 객체로 역직렬화
⑥ 애플리케이션 로직 실행
⑦ 처리 완료된 위치 저장 (Offset 커밋)
. . . . .
2) Offset 관리 메커니즘
Offset은 파티션 내에서 각 메시지의 위치를 나타내는 고유한 번호입니다.
| Offset 종류 | 설명 |
|---|---|
| Current Offset | Consumer가 현재 읽고 있는 위치 |
| Committed Offset | Consumer가 처리 완료를 확정한 위치 |
| Log End Offset (LEO) | 파티션의 마지막 메시지 위치 |
| High Water Mark | 모든 복제본에 복제 완료된 위치 |
// 자동 커밋 (기본값)
props.put("enable.auto.commit", "true");
props.put("auto.commit.interval.ms", "1000");
// 수동 커밋 (권장)
props.put("enable.auto.commit", "false");
// 처리 후 수동으로 커밋
consumer.commitSync(); // 동기 커밋
consumer.commitAsync(); // 비동기 커밋
props.put("enable.auto.commit", "true");
props.put("auto.commit.interval.ms", "1000");
// 수동 커밋 (권장)
props.put("enable.auto.commit", "false");
// 처리 후 수동으로 커밋
consumer.commitSync(); // 동기 커밋
consumer.commitAsync(); // 비동기 커밋
주의: 자동 커밋 사용 시 메시지 처리 중 오류가 발생해도 Offset이 커밋될 수 있어 메시지 유실 가능성이 있습니다. 중요한 데이터는 수동 커밋을 사용하는 것이 좋습니다.
. . . . .
3) Kafka의 주요 특징
(1) 높은 처리량 (High Throughput)
Kafka는 초당 수백만 건의 메시지를 처리할 수 있는 뛰어난 성능을 자랑합니다.
① 순차적 I/O - 디스크에 순차적으로 쓰기 때문에 매우 빠름
② Zero-Copy - 커널에서 네트워크로 직접 전송하여 불필요한 복사 제거
③ 배치 처리 - 여러 메시지를 묶어서 처리하여 오버헤드 감소
④ 압축 - 네트워크 대역폭 절약 (gzip, snappy, lz4 등)
(2) 확장성 (Scalability)
Kafka는 수평 확장이 매우 쉽습니다.
① 브로커 추가: 클러스터에 서버를 추가하여 용량 증가
② 파티션 증가: Topic의 파티션 수를 늘려 병렬 처리 향상
③ Consumer 추가: Consumer Group에 Consumer를 추가하여 처리 속도 향상
(3) 내구성 (Durability)
Kafka는 데이터 손실을 방지하기 위한 여러 메커니즘을 제공합니다.
① 디스크 저장 - 모든 메시지를 디스크에 저장
② 복제 (Replication) - 각 파티션을 여러 브로커에 복제 (보통 3개)
③ Leader-Follower 구조 - 리더 장애 시 팔로워가 리더로 승격
# Topic 생성 시 복제 계수 설정
kafka-topics.sh --create \
--bootstrap-server localhost:9092 \
--topic orders \
--partitions 3 \
--replication-factor 3
kafka-topics.sh --create \
--bootstrap-server localhost:9092 \
--topic orders \
--partitions 3 \
--replication-factor 3
(4) 데이터 보존 기간 설정
Kafka는 메시지를 일정 기간 동안 보관하여 재처리가 가능합니다.
① 시간 기반: 예) 7일 동안 보관
② 크기 기반: 예) 1GB까지 보관
③ Compaction: 같은 키의 최신 메시지만 보관
# 7일 동안 메시지 보관
log.retention.hours=168
# 1GB 크기 제한
log.retention.bytes=1073741824
# Compaction 설정
log.cleanup.policy=compact
log.retention.hours=168
# 1GB 크기 제한
log.retention.bytes=1073741824
# Compaction 설정
log.cleanup.policy=compact
#3. Kafka 설치 및 실전 사용법
Kafka를 실제로 설치하고 사용하는 방법을 알아보겠습니다. Docker Compose를 사용하면 가장 빠르고 쉽게 설치할 수 있습니다.
1) Docker를 이용한 Kafka 설치
# docker-compose.yml
version: '3.8'
services:
zookeeper:
image: confluentinc/cp-zookeeper:latest
environment:
ZOOKEEPER_CLIENT_PORT: 2181
ZOOKEEPER_TICK_TIME: 2000
ports:
- "2181:2181"
kafka:
image: confluentinc/cp-kafka:latest
depends_on:
- zookeeper
ports:
- "9092:9092"
environment:
KAFKA_BROKER_ID: 1
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
kafka-ui:
image: provectuslabs/kafka-ui:latest
ports:
- "8080:8080"
environment:
KAFKA_CLUSTERS_0_NAME: local
KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:9092
version: '3.8'
services:
zookeeper:
image: confluentinc/cp-zookeeper:latest
environment:
ZOOKEEPER_CLIENT_PORT: 2181
ZOOKEEPER_TICK_TIME: 2000
ports:
- "2181:2181"
kafka:
image: confluentinc/cp-kafka:latest
depends_on:
- zookeeper
ports:
- "9092:9092"
environment:
KAFKA_BROKER_ID: 1
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
kafka-ui:
image: provectuslabs/kafka-ui:latest
ports:
- "8080:8080"
environment:
KAFKA_CLUSTERS_0_NAME: local
KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:9092
# Docker Compose로 실행
docker-compose up -d
# 로그 확인
docker-compose logs -f kafka
# Kafka UI 접속
# 브라우저에서 http://localhost:8080 열기
docker-compose up -d
# 로그 확인
docker-compose logs -f kafka
# Kafka UI 접속
# 브라우저에서 http://localhost:8080 열기
. . . . .
2) CLI를 이용한 기본 사용법
(1) Topic 생성
# Topic 생성
kafka-topics.sh --create \
--bootstrap-server localhost:9092 \
--topic user-events \
--partitions 3 \
--replication-factor 1
# Topic 목록 확인
kafka-topics.sh --list \
--bootstrap-server localhost:9092
# Topic 상세 정보 확인
kafka-topics.sh --describe \
--bootstrap-server localhost:9092 \
--topic user-events
kafka-topics.sh --create \
--bootstrap-server localhost:9092 \
--topic user-events \
--partitions 3 \
--replication-factor 1
# Topic 목록 확인
kafka-topics.sh --list \
--bootstrap-server localhost:9092
# Topic 상세 정보 확인
kafka-topics.sh --describe \
--bootstrap-server localhost:9092 \
--topic user-events
(2) 메시지 발행과 소비
# Console Producer 실행
kafka-console-producer.sh \
--bootstrap-server localhost:9092 \
--topic user-events
# 메시지 입력 (엔터로 전송)
> {"userId": "user123", "action": "login"}
> {"userId": "user456", "action": "purchase", "amount": 50000}
# Console Consumer 실행 (처음부터 모든 메시지)
kafka-console-consumer.sh \
--bootstrap-server localhost:9092 \
--topic user-events \
--from-beginning
kafka-console-producer.sh \
--bootstrap-server localhost:9092 \
--topic user-events
# 메시지 입력 (엔터로 전송)
> {"userId": "user123", "action": "login"}
> {"userId": "user456", "action": "purchase", "amount": 50000}
# Console Consumer 실행 (처음부터 모든 메시지)
kafka-console-consumer.sh \
--bootstrap-server localhost:9092 \
--topic user-events \
--from-beginning
. . . . .
3) Spring Boot에서 Kafka 사용하기
// KafkaProducerConfig.java
@Configuration
public class KafkaProducerConfig {
@Bean
public ProducerFactory<String, String> producerFactory() {
Map<String, Object> configProps = new HashMap<>();
configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
configProps.put(ProducerConfig.ACKS_CONFIG, "all");
return new DefaultKafkaProducerFactory<>(configProps);
}
}
// UserEventProducer.java
@Service
public class UserEventProducer {
private final KafkaTemplate<String, String> kafkaTemplate;
public void sendUserEvent(UserEvent event) {
String topic = "user-events";
kafkaTemplate.send(topic, event.getUserId(), eventJson);
}
}
@Configuration
public class KafkaProducerConfig {
@Bean
public ProducerFactory<String, String> producerFactory() {
Map<String, Object> configProps = new HashMap<>();
configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
configProps.put(ProducerConfig.ACKS_CONFIG, "all");
return new DefaultKafkaProducerFactory<>(configProps);
}
}
// UserEventProducer.java
@Service
public class UserEventProducer {
private final KafkaTemplate<String, String> kafkaTemplate;
public void sendUserEvent(UserEvent event) {
String topic = "user-events";
kafkaTemplate.send(topic, event.getUserId(), eventJson);
}
}
// UserEventConsumer.java
@Component
public class UserEventConsumer {
@KafkaListener(topics = "user-events", groupId = "user-event-group")
public void consume(ConsumerRecord<String, String> record, Acknowledgment ack) {
try {
log.info("메시지 수신 - Key: {}, Value: {}", record.key(), record.value());
processUserEvent(record.value());
ack.acknowledge(); // 수동 커밋
} catch (Exception e) {
log.error("메시지 처리 실패", e);
}
}
}
@Component
public class UserEventConsumer {
@KafkaListener(topics = "user-events", groupId = "user-event-group")
public void consume(ConsumerRecord<String, String> record, Acknowledgment ack) {
try {
log.info("메시지 수신 - Key: {}, Value: {}", record.key(), record.value());
processUserEvent(record.value());
ack.acknowledge(); // 수동 커밋
} catch (Exception e) {
log.error("메시지 처리 실패", e);
}
}
}
. . . . .
4) Kafka Best Practice
(1) 파티션과 Consumer 수 최적화
주의: 파티션과 Consumer를 무작정 늘리면 안 됩니다! 하나의 파티션은 Consumer Group 내에서 하나의 Consumer만 읽을 수 있으므로, 파티션보다 많은 Consumer는 대기 상태가 되어 자원 낭비입니다.
필요한 파티션 수 = max(목표 처리량 / Producer 처리량, 목표 처리량 / Consumer 처리량)
예시:
- 목표 처리량: 1000 msg/sec
- Producer 처리량: 100 msg/sec
- Consumer 처리량: 50 msg/sec
파티션 수 = max(1000/100, 1000/50) = max(10, 20) = 20개
예시:
- 목표 처리량: 1000 msg/sec
- Producer 처리량: 100 msg/sec
- Consumer 처리량: 50 msg/sec
파티션 수 = max(1000/100, 1000/50) = max(10, 20) = 20개
(2) 메시지 유실 방지 설정
// Producer 메시지 손실 방지 설정
props.put(ProducerConfig.ACKS_CONFIG, "all"); // 모든 복제본 저장 확인
props.put(ProducerConfig.RETRIES_CONFIG, Integer.MAX_VALUE); // 무제한 재시도
props.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, true); // 중복 방지
// Consumer 안전한 설정
props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false); // 수동 커밋
props.put(ConsumerConfig.ISOLATION_LEVEL_CONFIG, "read_committed"); // 커밋된 메시지만
props.put(ProducerConfig.ACKS_CONFIG, "all"); // 모든 복제본 저장 확인
props.put(ProducerConfig.RETRIES_CONFIG, Integer.MAX_VALUE); // 무제한 재시도
props.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, true); // 중복 방지
// Consumer 안전한 설정
props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, false); // 수동 커밋
props.put(ConsumerConfig.ISOLATION_LEVEL_CONFIG, "read_committed"); // 커밋된 메시지만
(3) Consumer Lag 모니터링
Consumer Lag은 Consumer가 처리하지 못한 메시지 수를 의미하며, 시스템 상태를 파악하는 핵심 지표입니다.
# Consumer Lag 확인
kafka-consumer-groups.sh \
--bootstrap-server localhost:9092 \
--group user-event-group \
--describe
# 출력 예시
GROUP TOPIC PARTITION CURRENT-OFFSET LOG-END-OFFSET LAG
user-event-group user-events 0 1000 1050 50
kafka-consumer-groups.sh \
--bootstrap-server localhost:9092 \
--group user-event-group \
--describe
# 출력 예시
GROUP TOPIC PARTITION CURRENT-OFFSET LOG-END-OFFSET LAG
user-event-group user-events 0 1000 1050 50
① Lag > 10,000: 주의 (Consumer 성능 점검 필요)
② Lag > 50,000: 경고 (즉시 조치 필요)
③ Lag 지속 증가: 치명적 (시스템 장애 위험)
#4. 글로벌 기업의 Kafka 실전 사례
전 세계 유수의 기업들이 Kafka를 어떻게 활용하여 비즈니스 문제를 해결하고 있는지 알아보겠습니다.
1) LinkedIn - Kafka의 탄생지
LinkedIn은 2010년경 급격한 성장으로 시스템 간 복잡한 의존성, 데이터 파이프라인의 확장성 부족, 실시간 데이터 처리의 어려움 문제에 직면했습니다. 이를 해결하기 위해 Kafka를 직접 개발했습니다.
(1) Kafka 도입 효과
① 하루 1조 개 이상의 메시지 처리
② 7,000개 이상의 애플리케이션이 Kafka 사용
③ 시스템 간 의존성 90% 감소
④ 이벤트 기반 아키텍처로 전환 성공
(2) 사용 사례
① 활동 스트림: 사용자 행동 데이터 실시간 수집
② 메트릭 수집: 시스템 모니터링 데이터 집계
③ 로그 집계: 분산 시스템의 로그 통합
④ 검색 인덱싱: 실시간 검색 인덱스 업데이트
. . . . .
2) Netflix - 실시간 추천 시스템
Netflix는 전 세계 2억 명 이상의 사용자에게 개인화된 콘텐츠를 실시간으로 추천해야 했습니다.
(1) Netflix의 Kafka 사용 규모
① 하루 5000억 개의 이벤트 처리
② 36개 클러스터, 4,000개 이상의 브로커
③ 피크 시간대 초당 2,000만 건 메시지 처리
④ 초당 800만 건의 시청 이벤트 수집
(2) Kafka 활용
① 시청 이벤트 수집: 사용자가 어떤 콘텐츠를 시청하는지 실시간 추적
② 실시간 분석: 사용자 행동 패턴 즉시 분석
③ 추천 업데이트: 실시간 추천 알고리즘 피드백
④ 모니터링: 스트리밍 품질 실시간 모니터링
. . . . .
3) Uber - 실시간 위치 추적
Uber는 수백만 명의 드라이버와 승객의 위치를 실시간으로 추적하고 매칭해야 했습니다.
(1) Kafka 활용 사례
① 위치 업데이트 - 드라이버와 승객의 GPS 데이터 실시간 수집 (분당 수백만 건)
② 매칭 알고리즘 - 최적의 드라이버-승객 매칭
③ 요금 계산 - 실시간 동적 가격 책정
④ 이상 탐지 - 비정상 운행 패턴 감지
(2) 성과
① 매칭 시간 50% 단축
② 시스템 안정성 크게 향상
③ 실시간 데이터 기반 의사결정 가능
. . . . .
4) 실전 활용 시나리오
(1) 전자상거래 - 주문 처리 시스템
주문 발생 → Kafka Topic "orders"
↓
├─ 재고 관리 서비스 (재고 차감)
├─ 결제 서비스 (결제 처리)
├─ 배송 서비스 (배송 준비)
├─ 알림 서비스 (고객 알림)
└─ 분석 서비스 (매출 분석)
각 서비스가 독립적으로 처리하여 시스템 장애 격리
↓
├─ 재고 관리 서비스 (재고 차감)
├─ 결제 서비스 (결제 처리)
├─ 배송 서비스 (배송 준비)
├─ 알림 서비스 (고객 알림)
└─ 분석 서비스 (매출 분석)
각 서비스가 독립적으로 처리하여 시스템 장애 격리
(2) IoT - 센서 데이터 수집
수천 개의 IoT 센서 → Kafka "sensor-data"
↓
├─ 실시간 모니터링 (대시보드 업데이트)
├─ 이상 탐지 (임계값 초과 알람)
├─ 데이터 저장 (시계열 DB 저장)
└─ 예측 분석 (머신러닝 모델 학습)
↓
├─ 실시간 모니터링 (대시보드 업데이트)
├─ 이상 탐지 (임계값 초과 알람)
├─ 데이터 저장 (시계열 DB 저장)
└─ 예측 분석 (머신러닝 모델 학습)
(3) 금융 - 사기 탐지 시스템
금융 거래 발생 → Kafka "transactions"
↓
├─ 규칙 기반 검증 (즉시 차단)
├─ ML 모델 분석 (이상 패턴 감지)
├─ 리스크 스코어링 (위험도 계산)
└─ 감사 로그 (모든 거래 기록)
밀리초 단위 실시간 처리로 사기 방지
↓
├─ 규칙 기반 검증 (즉시 차단)
├─ ML 모델 분석 (이상 패턴 감지)
├─ 리스크 스코어링 (위험도 계산)
└─ 감사 로그 (모든 거래 기록)
밀리초 단위 실시간 처리로 사기 방지
. . . . .
5) Kafka vs 다른 메시지 큐 비교
| 비교 항목 | Kafka | RabbitMQ |
|---|---|---|
| 처리량 | 초당 수백만 건 (매우 높음) | 초당 수만 건 (중간) |
| 메시지 보관 | 디스크에 장기 보관 가능 | 소비 후 삭제 (일반적) |
| 재처리 | 과거 메시지 재처리 가능 | 재처리 어려움 |
| 복잡도 | 높음 (학습 곡선 있음) | 낮음 (쉬운 설정) |
| 사용 사례 | 대용량 실시간 스트리밍 | 작업 큐, RPC, 라우팅 |
선택 가이드: Kafka는 초당 수십만 건 이상의 높은 처리량이 필요하고, 메시지를 장기간 보관하고 재처리해야 하며, 실시간 스트림 처리 파이프라인을 구축할 때 선택합니다. RabbitMQ는 복잡한 라우팅 로직이 필요하고, 빠른 구축과 간단한 설정을 선호하며, 작업 큐 패턴을 구현할 때 선택합니다.
마무리
Apache Kafka는 현대 데이터 중심 애플리케이션에서 없어서는 안 될 핵심 기술이 되었습니다. LinkedIn에서 시작된 작은 프로젝트가 이제는 Netflix, Uber, Airbnb 등 글로벌 기업들의 데이터 인프라를 책임지는 핵심 플랫폼으로 자리잡았습니다.
Kafka의 핵심 가치:
① 높은 처리량 - 초당 수백만 건의 메시지를 빠르게 처리합니다.
② 확장성 - 수평 확장을 통한 유연한 성능 향상이 가능합니다.
③ 내구성 - 데이터 손실 방지와 장애 복구 능력을 갖추고 있습니다.
④ 실시간 처리 - 낮은 지연시간의 스트림 처리를 제공합니다.
⑤ 생태계 - 풍부한 도구와 활발한 커뮤니티 지원이 있습니다.
시작하기 전 체크리스트:
① 현재 시스템의 메시지 처리량과 요구사항을 분석하세요.
② Kafka가 정말 필요한지 다른 대안(RabbitMQ, Redis Pub/Sub)과 비교하세요.
③ 파티션과 복제 전략을 설계하세요.
④ 모니터링 및 알람 체계를 구축하세요.
⑤ 재해 복구 및 백업 전략을 수립하세요.
기억하세요: Kafka는 강력한 도구이지만 만능은 아닙니다. 프로젝트의 요구사항을 정확히 파악하고, Kafka가 적합한 솔루션인지 신중하게 판단하는 것이 중요합니다. 작은 규모의 프로젝트에서는 RabbitMQ나 Redis Pub/Sub 같은 더 간단한 솔루션이 적합할 수 있습니다.
Kafka를 마스터하는 여정은 길지만, 그만큼 가치 있는 투자입니다. 이 글이 여러분의 Kafka 학습 여정에 좋은 출발점이 되길 바랍니다!
출처: 이 글은 Apache Kafka 공식 문서(https://kafka.apache.org/documentation/)와 Confluent 공식 문서(https://docs.confluent.io/)를 참고하여 작성되었습니다.
#5. 자주 묻는 질문 (FAQ)
1) Q: Kafka는 언제 사용하는 것이 좋나요?
A: Kafka는 대용량 실시간 데이터 처리가 필요한 경우에 가장 적합합니다. 구체적으로 초당 수만 건 이상의 메시지를 처리해야 하거나, 메시지를 장기간 보관하고 재처리해야 하거나, 여러 시스템이 같은 데이터를 독립적으로 소비해야 하는 경우에 사용하세요. 반면 단순한 작업 큐나 초당 수백 건 정도의 작은 규모라면 RabbitMQ나 Redis Pub/Sub이 더 적합할 수 있습니다.
. . . . .
2) Q: Kafka와 RabbitMQ의 가장 큰 차이점은 무엇인가요?
A: 가장 큰 차이는 메시지 보관 방식과 처리량입니다. RabbitMQ는 메시지를 소비하면 큐에서 제거하는 전통적인 메시지 큐 방식이고, Kafka는 메시지를 디스크에 일정 기간 보관하여 여러 Consumer가 독립적으로 읽을 수 있는 이벤트 스트리밍 방식입니다. 처리량 측면에서 Kafka는 초당 수백만 건을 처리할 수 있지만, RabbitMQ는 초당 수만 건 정도입니다. Kafka는 복잡하지만 대규모 시스템에 적합하고, RabbitMQ는 간단하지만 중소 규모에 적합합니다.
. . . . .
3) Q: 파티션 수는 어떻게 결정해야 하나요?
A: 파티션 수는 목표 처리량을 기준으로 계산합니다. 필요한 파티션 수 = max(목표 처리량 / Producer 처리량, 목표 처리량 / Consumer 처리량)입니다. 예를 들어 초당 1000개 메시지를 처리해야 하고, Producer는 초당 100개, Consumer는 초당 50개를 처리한다면 max(10, 20) = 20개의 파티션이 필요합니다. 시작은 3-5개 파티션으로 시작하여 모니터링 후 조정하는 것이 좋습니다. 중요: 파티션 수는 늘릴 수는 있지만 줄일 수는 없으므로 신중하게 결정하세요.
. . . . .
4) Q: Consumer Group은 무엇이고 왜 필요한가요?
A: Consumer Group은 하나의 Topic을 함께 구독하는 Consumer들의 그룹입니다. 핵심 원칙은 하나의 파티션은 Consumer Group 내에서 오직 하나의 Consumer만 읽을 수 있다는 것입니다. 이를 통해 메시지 순서를 보장하면서도 병렬 처리가 가능합니다. 예를 들어 3개의 파티션이 있다면 3개의 Consumer를 두어 각각 하나씩 처리하게 하면 처리 속도가 3배 빨라집니다. 다른 Consumer Group은 같은 메시지를 독립적으로 읽을 수 있어 서로 다른 목적으로 같은 데이터를 사용할 수 있습니다.
. . . . .
5) Q: Offset 커밋은 자동과 수동 중 어떤 것을 사용해야 하나요?
A: 중요한 데이터는 반드시 수동 커밋을 사용하세요. 자동 커밋은 편리하지만 메시지 처리 중 오류가 발생해도 Offset이 커밋될 수 있어 메시지 유실 위험이 있습니다. 수동 커밋은 메시지 처리가 완전히 끝난 후에만 커밋하므로 안전합니다. 다만 처리 속도보다 안정성이 중요한지 판단이 필요합니다. 로그 수집 같이 일부 손실이 허용되는 경우는 자동 커밋을, 금융 거래나 주문 처리 같이 손실이 절대 안 되는 경우는 수동 커밋을 사용하세요.
. . . . .
6) Q: Kafka 메시지는 얼마나 오래 보관할 수 있나요?
A: Kafka는 시간 기반, 크기 기반, Compaction 세 가지 보존 정책을 제공합니다. 시간 기반은 설정한 기간(예: 7일) 동안 보관하고, 크기 기반은 설정한 용량(예: 1GB)까지 보관합니다. Compaction은 같은 키의 최신 메시지만 보관하여 변경 이력을 유지합니다. 기본값은 7일이며, 디스크 용량이 허용하는 한 무제한으로 보관할 수도 있습니다. 이를 통해 과거 데이터를 재처리하거나 새로운 Consumer가 과거 데이터부터 읽을 수 있습니다.
. . . . .
7) Q: Consumer Lag이란 무엇이고 왜 중요한가요?
A: Consumer Lag은 Producer가 생성한 메시지와 Consumer가 처리한 메시지 간의 차이를 의미합니다. 즉, Consumer가 처리하지 못한 메시지 수입니다. Lag이 지속적으로 증가하면 Consumer가 Producer의 속도를 따라가지 못한다는 의미이므로 심각한 문제입니다. Lag > 10,000이면 주의, Lag > 50,000이면 경고, Lag이 지속 증가하면 치명적 상황입니다. Consumer 수를 늘리거나 Consumer 성능을 개선하여 Lag을 줄여야 합니다.
. . . . .
8) Q: Kafka 설치가 복잡한데 관리형 서비스를 사용하는 것이 좋을까요?
A: 프로젝트 상황에 따라 다릅니다. 자체 설치는 초기 설정이 복잡하고 운영 부담이 있지만 비용이 저렴하고 완전한 제어가 가능합니다. 관리형 서비스(AWS MSK, Confluent Cloud)는 설치와 운영이 간편하고 자동 확장과 백업을 제공하지만 비용이 비쌀 수 있습니다. 소규모 프로젝트나 Kafka 전문가가 없는 팀은 관리형 서비스를, 대규모 프로젝트나 비용 최적화가 중요한 경우는 자체 설치를 고려하세요. 학습 목적이라면 Docker Compose로 로컬 설치가 가장 좋습니다.
. . . . .
9) Q: Kafka는 메시지 순서를 보장하나요?
A: 파티션 내에서만 순서가 보장됩니다. 같은 파티션에 저장된 메시지들은 저장된 순서대로 읽히지만, 서로 다른 파티션 간에는 순서가 보장되지 않습니다. 따라서 순서가 중요한 메시지는 같은 키를 사용하여 같은 파티션으로 보내야 합니다. 예를 들어 특정 사용자의 모든 이벤트 순서를 보장하려면 userId를 키로 사용하세요. 전체 Topic에서 순서를 보장하려면 파티션을 1개만 사용해야 하지만, 이는 병렬 처리를 포기하는 것이므로 권장하지 않습니다.
. . . . .
10) Q: Kafka를 학습하는 데 얼마나 시간이 걸리나요?
A: 기본 개념 이해와 간단한 Producer/Consumer 작성까지는 1-2주 정도면 충분합니다. 하지만 클러스터 구성, 성능 최적화, 장애 대응, 모니터링까지 마스터하려면 수개월이 걸릴 수 있습니다. 효과적인 학습 방법은: ① Docker로 로컬 환경 구축 → ② CLI로 Topic 생성 및 메시지 송수신 실습 → ③ Java나 Python으로 Producer/Consumer 작성 → ④ 실제 프로젝트에 적용하며 경험 쌓기입니다. 공식 문서와 Confluent의 튜토리얼이 매우 잘 되어 있으니 활용하세요.
긴 글 읽어주셔서 감사합니다.
끝.
끝.
반응형
'Development > Web' 카테고리의 다른 글
| [Web] Apache Airflow DAG 사용법 및 서버 연동 방법 (0) | 2025.10.31 |
|---|---|
| [Web] Apache Airflow 워크플로우 자동화 방법 (0) | 2025.10.30 |
| [Web] Spring Boot 3.4 + AWS 환경 Tomcat vs JBoss WildFly 성능 비교 분석 (3) | 2025.04.07 |
| [Web] JEUS DB Connection Leak 완벽 해결 방법 (0) | 2024.07.24 |
| [Web] Spring Dispatcher Servlet 정의와 동작 원리 (0) | 2022.09.24 |