“우리 서비스에 접속자가 갑자기 폭증했는데, 시스템이 버텨내지 못하고 다운됐어요…” “주문이 들어왔는데 재고 시스템에는 반영이 안 됐어요…” “로그가 너무 많아서 실시간으로 확인할 수가 없어요…” 이런 문제들, 혹시 겪어보셨나요? 오늘 소개할 Apache Kafka(아파치 카프카)가 바로 이런 고민을 해결해주는 도구입니다. 처음부터 차근차근, 쉽게 알아볼게요.

 

 

 

1. Kafka가 뭔가요? – 우체국에 비유하면

일단 간단하게 설명하면, Kafka는 초고속 우체국 같은 거예요.

일반 우체국은 이렇게 동작하죠

보내는 사람 → 우체국 → 받는 사람

한 명이 편지를 보내면, 한 명이 받습니다. 받는 사람이 편지를 읽으면 끝이죠.

Kafka 우체국은 조금 달라요

보내는 사람들 → Kafka → 여러 받는 사람들
(여러 명)           (보관함)   (각자 복사본을 받음)

특별한 점:

  1. 하루에 수백만 통의 편지를 처리할 수 있어요 (엄청난 속도)
  2. 편지를 일정 기간 보관해서, 나중에 다시 읽을 수 있어요
  3. 한 편지를 여러 사람이 각각 읽을 수 있어요
  4. 편지가 분실되지 않게 여러 곳에 복사본을 만들어요

이게 바로 Kafka가 하는 일입니다!

실제 사례로 이해하기

쿠팡에서 주문 버튼을 누르는 순간:

① 주문 시스템: "주문이 들어왔어요!" → Kafka에 메시지 전송

② Kafka가 이 메시지를 여러 시스템에 동시에 전달:
   - 재고 시스템: "재고 1개 빼야겠네"
   - 결제 시스템: "카드 결제 진행해야겠네"
   - 배송 시스템: "배송 준비해야겠네"
   - 알림 시스템: "고객에게 문자 보내야겠네"
   - 분석 시스템: "오늘 매출에 추가해야겠네"

만약 Kafka가 없었다면:

  • 주문 시스템이 5개 시스템에 일일이 연결해서 전달해야 함
  • 결제 시스템이 다운되면? 주문 시스템도 멈춤
  • 나중에 추천 시스템을 추가하려면? 주문 시스템 코드를 수정해야 함

Kafka가 있으면:

  • 주문 시스템은 Kafka에만 보내면 끝
  • 각 시스템은 독립적으로 동작
  • 새 시스템 추가? 그냥 Kafka에서 읽기만 하면 됨

 

 

2. 왜 Kafka를 만들었을까? – 링크드인의 고민

2011년 링크드인은 큰 문제가 있었어요.

복잡하게 얽힌 시스템들

[시스템 구조]

회원가입 시스템 ─┬→ 이메일 시스템
                ├→ 추천 시스템
                ├→ 검색 시스템
                └→ 분석 시스템

이메일 시스템 ──┬→ 알림 시스템
               └→ 로그 시스템

추천 시스템 ────┬→ 분석 시스템
               └→ 검색 시스템

문제점:

  • 시스템이 20개면 연결이 수백 개
  • 한 시스템에 문제가 생기면 연결된 모든 시스템 확인 필요
  • 새 시스템 추가할 때마다 기존 시스템들과 연결 작업
  • 하루 14억 개 메시지 처리하다 보니 시스템이 버티기 힘들었음

Kafka로 단순화

[Kafka 도입 후]

회원가입 시스템 ─┐
이메일 시스템 ───┤
추천 시스템 ─────┤→ Kafka ─┤→ 알림 시스템
검색 시스템 ─────┤         ├→ 로그 시스템
분석 시스템 ─────┘         ├→ 검색 시스템
                          └→ 추천 시스템

개선 효과:

  • 모든 시스템이 Kafka하고만 통신
  • 한 시스템 장애가 다른 시스템에 영향 없음
  • 새 시스템 추가가 간단함
  • 초당 수백만 메시지도 문제없이 처리

 

 

3. Kafka의 핵심 개념 – 실생활로 이해하기

Producer (생산자) = 편지 보내는 사람

데이터를 만들어서 Kafka로 보내는 애플리케이션이에요.

실제 예시:

  • 웹 서버: “사용자가 상품 페이지를 봤어요”
  • 모바일 앱: “사용자가 앱을 열었어요”
  • IoT 센서: “현재 온도는 25도예요”
  • 주문 시스템: “새 주문이 들어왔어요”

Consumer (소비자) = 편지 받는 사람

Kafka에서 데이터를 읽어서 처리하는 애플리케이션이에요.

실제 예시:

  • 추천 시스템: 클릭 데이터를 읽어서 → 추천 알고리즘 업데이트
  • 알림 시스템: 주문 데이터를 읽어서 → 고객에게 문자 발송
  • 모니터링 시스템: 에러 로그를 읽어서 → 담당자에게 알림

Topic (토픽) = 우편함의 라벨

메시지를 종류별로 분류하는 카테고리예요. 도서관의 책장 라벨과 비슷해요.

[Kafka Topics]

📬 user.signup      (회원가입 이벤트)
📬 order.created    (주문 생성 이벤트)
📬 payment.success  (결제 완료 이벤트)
📬 sensor.temp      (온도 센서 데이터)

각 시스템은 필요한 토픽만 구독하면 됩니다.

Partition (파티션) = 여러 개의 창구

토픽을 여러 조각으로 나눈 거예요. 은행 창구를 생각해보세요.

[은행 비유]

창구가 1개일 때:
대기자 100명 → 창구 1개 → 100분 소요

창구가 5개일 때:
대기자 100명 → 창구 5개 → 20분 소요

Kafka도 똑같아요:

[주문 토픽 - 1개 파티션]
주문 1, 2, 3, 4, 5... → 파티션 0 → 처리 느림

[주문 토픽 - 3개 파티션]
주문 1, 4, 7... → 파티션 0 ↘
주문 2, 5, 8... → 파티션 1 → 동시 처리 → 3배 빠름!
주문 3, 6, 9... → 파티션 2 ↗

어떻게 나눠질까요?

  1. 키가 있으면: 같은 키는 항상 같은 파티션
    user123의 모든 활동 → 항상 파티션 0
    user456의 모든 활동 → 항상 파티션 1
    

    순서가 중요할 때 사용해요.

  2. 키가 없으면: 골고루 분배
    메시지 1 → 파티션 0
    메시지 2 → 파티션 1
    메시지 3 → 파티션 2
    메시지 4 → 파티션 0
    

Offset (오프셋) = 책의 페이지 번호

각 메시지의 위치를 나타내는 번호예요.

[파티션 0의 메시지들]

오프셋:  0      1      2      3      4      5
메시지: [주문1] [주문4] [주문7] [주문10] [주문13] [주문16]
                              ↑
                        여기까지 읽음 (오프셋 3)

왜 중요할까요?

책을 읽다가 표시해둔 것처럼:

  • “어디까지 읽었지?” → 오프셋으로 확인
  • 시스템이 재시작되어도 → 이어서 읽을 수 있음
  • 잘못 읽었다면? → 오프셋을 되돌려서 다시 읽기

Broker (브로커) = 우체국 지점

실제로 메시지를 저장하고 관리하는 Kafka 서버예요.

[단일 Broker - 위험]
브로커 1개 → 고장나면 전체 중단 ❌

[클러스터 - 안전]
브로커 1 (메시지 A, B 저장)
브로커 2 (메시지 A, B 복사본)
브로커 3 (메시지 A, B 복사본)
→ 1~2개 고장나도 서비스 정상 ✓

Consumer Group (소비자 그룹) = 협업하는 팀

여러 Consumer가 팀을 이루어 일을 나눠서 처리해요.

[주문 처리 팀 - 4명이 협업]

주문 토픽 (4개 파티션)
├─ 파티션 0 → 직원 A가 처리
├─ 파티션 1 → 직원 B가 처리
├─ 파티션 2 → 직원 C가 처리
└─ 파티션 3 → 직원 D가 처리

결과: 4배 빠른 처리!

중요한 규칙:

  • 한 파티션은 그룹 내 한 명만 처리 가능
  • 직원이 5명인데 파티션이 4개? → 1명은 대기
  • 직원이 2명인데 파티션이 4개? → 1명당 2개씩 처리

다른 팀은 독립적:

[주문 데이터를 각 팀이 독립적으로 사용]

주문 토픽
├─ 배송 팀: 배송지 준비
├─ 분석 팀: 매출 집계
└─ 알림 팀: 고객 문자 발송

(각 팀은 서로 영향 없이 독립적으로 처리)

Replication (복제) = 백업

데이터를 여러 Broker에 복사해서 안전하게 보관해요.

[Replication Factor = 3]

파티션 0 원본 (Leader)    → 브로커 1
파티션 0 복사본 (Follower) → 브로커 2
파티션 0 복사본 (Follower) → 브로커 3

브로커 1이 고장나면?

① 브로커 1 다운 🔴
② 브로커 2가 즉시 Leader로 승격 ✓
③ 서비스 중단 없이 계속 동작
④ 브로커 3에서 새 복사본 생성

 

 

4. Kafka가 빠른 이유 – 핵심 비결

비결 1: 디스크를 순차적으로 사용

랜덤 쓰기 (느림):

디스크 여기저기 왔다갔다
위치 찾기 → 쓰기 → 위치 찾기 → 쓰기
시간이 오래 걸림

순차 쓰기 (빠름):

디스크에 쭉 이어서 쓰기
쓰기 → 쓰기 → 쓰기 → 쓰기
하드디스크도 SSD처럼 빠름!

Kafka는 메시지를 파일 끝에 계속 추가만 해요. 그래서 빠릅니다.

비결 2: 배치 처리

개별 전송 (비효율):

메시지 1개 → 전송 (네트워크 왕복)
메시지 1개 → 전송 (네트워크 왕복)
메시지 1개 → 전송 (네트워크 왕복)
총 3번의 네트워크 왕복

배치 전송 (효율적):

메시지 100개 모아서 → 한 번에 전송
1번의 네트워크 왕복으로 100개 처리!

비결 3: Zero-Copy

일반적인 방식:

디스크 → 커널 메모리 → 애플리케이션 메모리 → 소켓 버퍼 → 네트워크
(4번 복사)

Kafka의 Zero-Copy:

디스크 → 네트워크
(복사 최소화)

CPU와 메모리를 거의 사용하지 않고 데이터를 전송해요.

비결 4: 파티션 병렬 처리

1개 파티션 = 1명이 일함 → 느림
10개 파티션 = 10명이 동시에 일함 → 10배 빠름

 

 

5. Kafka 4.0의 혁신 – 더 쉽고 강력해졌어요

ZooKeeper 없이도 동작! (KRaft 모드)

과거 (복잡했던 시절):

① ZooKeeper 클러스터 설치 (3대)
② Kafka 클러스터 설치 (3대)
③ ZooKeeper와 Kafka 연결 설정
④ 둘 다 관리하고 모니터링

지금 (간단해진 시대):

① Kafka만 설치하면 끝!
② 설정도 훨씬 간단
③ 관리할 시스템이 절반으로

KRaft의 장점:

[비교]

ZooKeeper 시절:
- 최대 파티션: 10만 개
- 클러스터 시작 시간: 수 분
- 관리 복잡도: 높음

KRaft 시대:
- 최대 파티션: 수백만 개
- 클러스터 시작 시간: 수 초
- 관리 복잡도: 낮음

리밸런싱이 훨씬 부드러워졌어요 (KIP-848)

과거의 문제:

① 새 Consumer 추가
② 모든 Consumer 멈춤 🛑
③ 파티션 재분배
④ 모든 Consumer 재시작
⑤ 10초 동안 처리 중단...

지금은 이렇게:

① 새 Consumer 추가
② 필요한 파티션만 조금씩 이동
③ 나머지 Consumer는 계속 처리 ✓
④ 100ms 정도만 지연

실제 체감:

  • 과거: “어? 갑자기 처리가 멈췄네?”
  • 지금: “언제 Consumer 추가된 거지?” (못 느낌)

Queue 기능 추가! (Share Group)

기존 Kafka:

파티션 0 → Consumer A만 읽을 수 있음
파티션 1 → Consumer B만 읽을 수 있음

Share Group (새로운 기능):

파티션 0 → Consumer A, B, C 모두 협력해서 처리
(메시지별로 한 명씩만 처리, RabbitMQ처럼!)

언제 유용할까요?

[택시 호출 시스템]

호출 요청 100건이 파티션 0에 들어옴
→ 매칭 서버 A, B, C가 협력
→ A가 30건, B가 35건, C가 35건 처리
→ 병렬 처리로 빠른 매칭!

 

 

6. 실제로 사용해보기 – 단계별 가이드

준비: Java 17

# Ubuntu/Debian
sudo apt-get update
sudo apt-get install openjdk-17-jdk

# 확인
java -version
# openjdk version "17.0.x" 나오면 성공!

Kafka 다운로드

# 최신 버전 다운로드
wget https://downloads.apache.org/kafka/4.1.0/kafka_2.13-4.1.0.tgz

# 압축 풀기
tar -xzf kafka_2.13-4.1.0.tgz
cd kafka_2.13-4.1.0

Kafka 시작 (정말 간단해요!)

# 1단계: ID 생성 (맨 처음 한 번만)
KAFKA_CLUSTER_ID="$(bin/kafka-storage.sh random-uuid)"

# 2단계: 저장소 준비
bin/kafka-storage.sh format -t $KAFKA_CLUSTER_ID -c config/kraft/server.properties

# 3단계: Kafka 시작!
bin/kafka-server-start.sh config/kraft/server.properties

화면에 이렇게 나오면 성공:

[KafkaServer id=1] started

토픽 만들기 – 우편함 만들기

새 터미널을 열어서:

bin/kafka-topics.sh --create \
  --topic hello-kafka \
  --bootstrap-server localhost:9092 \
  --partitions 3 \
  --replication-factor 1

해석해볼까요?

  • hello-kafka: 우편함 이름
  • partitions 3: 창구 3개 (3배 빠른 처리)
  • replication-factor 1: 복사본 1개 (혼자 실습이라 1개)

메시지 보내기 – 첫 편지 쓰기

bin/kafka-console-producer.sh \
  --topic hello-kafka \
  --bootstrap-server localhost:9092

이제 입력할 수 있어요:

> 안녕 Kafka!
> 첫 번째 메시지예요
> 실시간으로 전달될까요?

한 줄씩 입력하고 Enter! 각 줄이 하나의 메시지가 됩니다.

메시지 받기 – 편지 읽기

또 다른 터미널을 열어서:

bin/kafka-console-consumer.sh \
  --topic hello-kafka \
  --from-beginning \
  --bootstrap-server localhost:9092

아까 보낸 메시지들이 화면에 나타나요!

안녕 Kafka!
첫 번째 메시지예요
실시간으로 전달될까요?

실시간 테스트 해보기

Producer 터미널과 Consumer 터미널을 양옆에 나란히 놓고:

Producer에서 입력:

> 실시간 테스트!

Consumer에서 거의 즉시 출력:

실시간 테스트!

신기하죠? 이게 Kafka의 실시간 처리 능력입니다!

 

 

7. Docker로 더 쉽게 시작하기

설치 과정이 번거롭다면 Docker를 사용해보세요.

docker-compose.yml 파일 만들기

version: '3.8'
services:
  kafka:
    image: apache/kafka:4.0.0
    container_name: my-kafka
    ports:
      - "9092:9092"
    environment:
      # KRaft 모드 설정
      KAFKA_NODE_ID: 1
      KAFKA_PROCESS_ROLES: broker,controller
      KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
      KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT
      KAFKA_CONTROLLER_QUORUM_VOTERS: 1@localhost:9093
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
      KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1
      KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1
      KAFKA_LOG_DIRS: /tmp/kraft-combined-logs
      CLUSTER_ID: MkU3OEVBNTcwNTJENDM2Qk

실행하기

# Kafka 시작
docker-compose up -d

# 잘 동작하는지 확인
docker-compose logs -f

# 토픽 만들기
docker exec -it my-kafka kafka-topics.sh \
  --create --topic test \
  --bootstrap-server localhost:9092 \
  --partitions 3

# 종료
docker-compose down

이게 끝! 정말 간단하죠?

 

 

8. 실제 코드로 사용하기

Python으로 메시지 보내기

from kafka import KafkaProducer
import json
from datetime import datetime

# Producer 생성
producer = KafkaProducer(
    bootstrap_servers=['localhost:9092'],
    value_serializer=lambda v: json.dumps(v).encode('utf-8')
)

# 주문 데이터 보내기
order = {
    '주문번호': 'ORD-001',
    '상품': '노트북',
    '수량': 1,
    '가격': 1500000,
    '시간': datetime.now().isoformat()
}

# Kafka로 전송!
future = producer.send('orders', value=order)

# 전송 완료 확인
result = future.get(timeout=10)
print(f'전송 완료! 파티션: {result.partition}, 오프셋: {result.offset}')

producer.close()

실행 결과:

전송 완료! 파티션: 2, 오프셋: 15

Python으로 메시지 받기

from kafka import KafkaConsumer
import json

# Consumer 생성
consumer = KafkaConsumer(
    'orders',
    bootstrap_servers=['localhost:9092'],
    auto_offset_reset='earliest',  # 처음부터 읽기
    group_id='order-processor',    # 그룹 이름
    value_deserializer=lambda x: json.loads(x.decode('utf-8'))
)

print('주문을 기다리는 중...')

# 메시지 받아서 처리
for message in consumer:
    order = message.value
    print(f'\n새 주문 도착!')
    print(f'주문번호: {order["주문번호"]}')
    print(f'상품: {order["상품"]}')
    print(f'수량: {order["수량"]}')
    print(f'가격: {order["가격"]:,}원')

실행 결과:

주문을 기다리는 중...

새 주문 도착!
주문번호: ORD-001
상품: 노트북
수량: 1
가격: 1,500,000원

Java 간단 예제

Producer:

import org.apache.kafka.clients.producer.*;
import java.util.Properties;

public class OrderProducer {
    public static void main(String[] args) {
        // 설정
        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 생성
        Producer<String, String> producer = new KafkaProducer<>(props);
        
        // 메시지 전송
        String orderId = "ORD-001";
        String orderData = "노트북,1,1500000";
        
        ProducerRecord<String, String> record = 
            new ProducerRecord<>("orders", orderId, orderData);
        
        producer.send(record, (metadata, exception) -> {
            if (exception == null) {
                System.out.println("전송 성공! 파티션: " + 
                    metadata.partition() + ", 오프셋: " + metadata.offset());
            } else {
                System.out.println("전송 실패: " + exception.getMessage());
            }
        });
        
        producer.close();
    }
}

 

 

9. 실무 활용 사례 – 쉽게 이해하기

사례 1: 배달 앱의 실시간 주문 처리

[고객이 치킨을 주문하는 순간]

① 주문 앱 → Kafka (order.created)
   "강남구에서 치킨 1마리 주문"

② Kafka에서 여러 시스템이 동시에 읽음:

   매칭 시스템:
   "가까운 가게 3곳 찾았어요!"
   
   결제 시스템:
   "카드 결제 완료했어요!"
   
   알림 시스템:
   "고객에게 '주문 접수됐어요' 문자 보냄"
   "가게에 '새 주문이요!' 알림 보냄"
   
   실시간 지도:
   "배달 현황 지도에 표시"

왜 Kafka를 쓸까요?

  • 초당 수천 건의 주문도 처리 가능
  • 한 시스템이 느려도 다른 시스템은 정상 동작
  • 피크 시간대(저녁 6~8시)에도 안정적

사례 2: 넷플릭스의 추천 시스템

[드라마를 보는 순간순간]

사용자 행동:
- 5초간 미리보기 봄 → Kafka
- 드라마 재생 시작 → Kafka
- 10분 시청 → Kafka
- 일시정지 → Kafka
- 이어보기 클릭 → Kafka

실시간 처리:
- 추천 모델 즉시 업데이트
- "이런 드라마는 어때요?" 갱신
- 시청 패턴 분석
- 다음 에피소드 미리 로드

사례 3: 쿠팡의 재고 관리

[실시간 재고 동기화]

A 지역 창고: "노트북 10대 남음" → Kafka
B 지역 창고: "노트북 5대 남음" → Kafka
C 지역 창고: "노트북 0대 (품절)" → Kafka

→ 웹사이트에 실시간 반영
→ 모바일 앱에 실시간 반영
→ 상품 검색 결과에 반영
→ 판매 가능 수량 계산

효과:

  • 품절 상품 주문 방지
  • 과다 재고 방지
  • 고객 만족도 향상

사례 4: 카카오뱅크의 이체 처리

[100만원 이체하는 순간]

① 이체 요청 → Kafka
② 여러 시스템이 동시에 처리:

   잔액 확인: "잔액 충분한가요?"
   한도 확인: "일일 한도 내인가요?"
   사기 탐지: "의심스러운 거래인가요?"
   이체 실행: "송금 완료!"
   알림 발송: "100만원 이체됐어요"
   회계 처리: "거래 내역 기록"

 

 

10. 자주 묻는 질문들

Q1. 파티션은 몇 개로 설정해야 하나요?

간단한 계산법:

목표 처리량이 초당 10,000개라면?

1. Consumer 한 개가 처리하는 속도 측정
   → 예: 초당 2,000개

2. 필요한 Consumer 수 계산
   → 10,000 ÷ 2,000 = 5개

3. 파티션 수 = Consumer 수
   → 파티션 5개로 설정!

4. 여유분 추가 (1.5배)
   → 최종: 파티션 7~8개

경험상 권장:

  • 테스트/개발: 3개
  • 소규모 서비스: 5~10개
  • 중규모 서비스: 20~50개
  • 대규모 서비스: 100개 이상

Q2. 메시지를 얼마나 보관해야 하나요?

용도별 가이드:

실시간 알림:
보존 기간 1일
(하루 지난 알림은 의미 없음)

주문 데이터:
보존 기간 30일
(환불, 교환 등을 위해)

로그 데이터:
보존 기간 7일
(분석 후 버림)

중요 이벤트:
보존 기간 무제한
(재처리나 감사를 위해)

설정 방법:

# 7일 보관
bin/kafka-configs.sh --alter \
  --entity-type topics \
  --entity-name my-topic \
  --add-config retention.ms=604800000 \
  --bootstrap-server localhost:9092

Q3. Consumer Lag이 뭔가요?

쉽게 설명하면:

[상황]

Producer: 메시지 100개 보냄
Consumer: 메시지 70개 읽음

→ Lag = 30개 (처리해야 할 메시지가 30개 남음)

비유:

식당 주방:
- 주문이 10개 들어옴 (Producer)
- 요리사가 7개 만듦 (Consumer)
- 대기 주문 3개 (Lag)

Lag이 계속 증가하면?
→ 주문이 밀린다!
→ 요리사를 더 투입해야 함 (Consumer 추가)

확인 방법:

bin/kafka-consumer-groups.sh \
  --bootstrap-server localhost:9092 \
  --group my-group \
  --describe

결과:

TOPIC     PARTITION  LAG
orders    0          0      (좋음!)
orders    1          150    (처리가 밀림!)
orders    2          5      (괜찮음)

Q4. Replication Factor는 어떻게 설정하나요?

상황별 권장:

개발/테스트:
Replication Factor = 1
(혼자 테스트하니까 복사본 불필요)

소규모 운영:
Replication Factor = 2
(하나 고장나도 버틸 수 있음)

중요한 운영:
Replication Factor = 3
(두 개 동시 고장나도 버팀, 추천!)

미션 크리티컬:
Replication Factor = 5
(금융권 등 절대 잃으면 안 되는 데이터)

실제 설정:

bin/kafka-topics.sh --create \
  --topic important-data \
  --partitions 10 \
  --replication-factor 3 \
  --bootstrap-server localhost:9092

Q5. Kafka vs Redis, 뭘 써야 하나요?

용도별 선택:

Redis (Pub/Sub):
✓ 메시지 보관 안 함 (휘발성)
✓ 초저지연 (마이크로초)
✓ 간단한 알림
✗ 메시지 유실 가능
예: 채팅 읽음 표시, 실시간 알림

Kafka:
✓ 메시지 영구 보관
✓ 대용량 처리
✓ 여러 Consumer
✓ 데이터 유실 없음
✗ 약간 무거움
예: 주문 처리, 로그 수집, 이벤트 소싱

함께 사용하는 경우:

주문 시스템:
주문 데이터 → Kafka (영구 보관)
실시간 알림 → Redis (빠른 푸시)

 

 

11. 자주 접하는 문제 해결 – 막힐 때 이렇게 하세요!

문제 1: “Connection refused” 에러

증상:

Error connecting to node localhost:9092

원인과 해결:

# 1. Kafka가 실행 중인지 확인
ps aux | grep kafka

# 안 뜨면 시작
bin/kafka-server-start.sh config/kraft/server.properties

# 2. 포트가 사용 중인지 확인
lsof -i :9092

# 다른 프로세스가 쓰고 있으면 종료
kill -9 <PID>

문제 2: Consumer Lag이 계속 증가

원인:

Producer: 초당 10,000개 생산
Consumer: 초당 3,000개 처리
→ 초당 7,000개씩 밀림!

해결 1: Consumer 추가

# 원래: Consumer 2개
# 변경: Consumer 5개로 증가

# 그러면 파티션도 충분한지 확인!
bin/kafka-topics.sh --describe --topic my-topic

# 파티션이 3개면 Consumer 5개는 의미 없음
# 파티션을 먼저 늘리기
bin/kafka-topics.sh --alter \
  --topic my-topic \
  --partitions 10

해결 2: Consumer 처리 속도 개선

# Before: 메시지마다 DB에 저장 (느림)
for message in consumer:
    save_to_db(message)  # 매번 DB 접근

# After: 배치로 모아서 저장 (빠름)
batch = []
for message in consumer:
    batch.append(message)
    if len(batch) >= 100:
        save_batch_to_db(batch)  # 100개씩 한 번에
        batch = []

문제 3: 메모리 부족 에러

증상:

java.lang.OutOfMemoryError: Java heap space

해결:

# Kafka 힙 메모리 늘리기
export KAFKA_HEAP_OPTS="-Xmx2G -Xms2G"

# 재시작
bin/kafka-server-start.sh config/kraft/server.properties

문제 4: 디스크 용량 부족

확인:

df -h

해결:

# 보존 기간 단축 (30일 → 7일)
bin/kafka-configs.sh --alter \
  --entity-type topics \
  --entity-name my-topic \
  --add-config retention.ms=604800000

# 또는 사이즈 제한
bin/kafka-configs.sh --alter \
  --entity-type topics \
  --entity-name my-topic \
  --add-config retention.bytes=10737418240

 

 

12. 다음 단계 – 더 배우고 싶다면

무료 학습 자료

공식 문서:

무료 강의:

무료 실습:

관리 도구

Kafka UI (무료):

docker run -p 8080:8080 \
  -e KAFKA_CLUSTERS_0_NAME=local \
  -e KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS=localhost:9092 \
  provectuslabs/kafka-ui:latest

웹 브라우저로 http://localhost:8080 접속하면:

  • 토픽 목록 보기
  • 메시지 확인
  • Consumer Group 상태 모니터링
  • 시각적으로 관리 가능!

 

 

마무리하며…

Kafka는 처음엔 어려워 보이지만, 핵심만 이해하면 정말 강력한 도구입니다.

기억해야 할 핵심:

  1. Kafka = 초고속 우체국
    • 많은 편지를 빠르게 전달
    • 여러 사람이 같은 편지 읽을 수 있음
  2. 파티션 = 창구
    • 많을수록 빠름
    • Consumer 수와 맞춰야 함
  3. 오프셋 = 책갈피
    • 어디까지 읽었는지 기억
    • 실패해도 이어서 읽기 가능
  4. Replication = 백업
    • 데이터 안전하게 보관
    • 서버 고장도 문제없음

Kafka 4.0부터는 ZooKeeper도 없어져서 훨씬 쉬워졌어요. 지금이 시작하기 딱 좋은 시점입니다!

작은 프로젝트부터 시작해보세요. 로그 수집이나 간단한 이벤트 처리부터 해보면서 익숙해지면, 점점 더 큰 시스템에 적용할 수 있을 거예요. 🙂

 

 

 

댓글 남기기