Kafka는 어떤 문제를 해결했나? 등장 전후 비교

들어가며

2011년 LinkedIn이 Kafka를 오픈소스로 공개했을 때, 시스템 아키텍처의 세계는 어떤 모습이었을까? 이 글에서는 Kafka 등장 전 우리가 직면했던 문제들과, Kafka가 어떻게 그것을 해결했는지 살펴본다.

Kafka 등장 전: 전통적인 데이터 파이프라인의 악몽

1. 전통적인 ETL 패러다임

ETL이란?

  • Extract: 다양한 소스에서 데이터 추출
  • Transform: 데이터 정제 및 변환
  • Load: 데이터웨어하우스나 분석 시스템에 저장
[결제 시스템]  [로그 서버]  [고객 DB]  [웹 분석]
      ↓            ↓          ↓        ↓
  [배치 ETL 작업 1]      [배치 ETL 작업 2]
  (매일 자정 실행)       (매일 2시 실행)
      ↓                    ↓
[데이터 웨어하우스]
      ↓
[분석 대시보드] (새벽 4시쯤에야 업데이트)

2. 전통적 파이프라인의 문제점들

문제 1: 시간 지연 (Latency)

- 결제 완료: 오후 3시 15분
- ETL 스케줄: 매일 자정 (오후 12시)
- 데이터 나타남: 다음날 아침 1시
→ 21시간 45분의 지연!

현실: 마케팅팀이 오후에 "어제 매출은?" 물어봐도 답할 수 없음

실제 리포팅 사이클:

[실시간 발생] → 기다림(최대 24시간) → [분석] → [의사결정]

→ 시장 변화에 너무 늦게 대응

문제 2: 비효율적인 리소스 사용

배치 작업의 낭비:

새벽 자정부터 새벽 4시까지만 실행
- 자정~1시: 결제 데이터 추출 (1시간)
  └─ 이 시간에만 리소스 독점
- 1시~2시: 로그 데이터 처리 (1시간)
- 2시~3시: 집계 및 변환 (1시간)
- 3시~4시: 데이터웨어하우스 로드 (1시간)

→ 서버는 낮 시간에 유휴 상태
→ 갑자기 데이터 몰려도 처리 불가 (다음날까지 기다려야 함)

문제 3: 강한 결합도와 운영 복잡도

각 소스마다 별도의 ETL 스크립트 필요:

# etl_payment.py
def extract_payments():
    db.connect()
    data = db.query("SELECT * FROM payments WHERE date = yesterday")
    return data

def transform(data):
    # 통화 변환, 중복 제거, 포맷 변환
    return cleaned_data

def load(data):
    warehouse.insert(data)

# 만약 결제 스키마 변경되면?
# → etl_payment.py 수정 필요
# → etl_customer.py도 영향 받으면 또 수정
# → 변수명 일관성, 로직 중복, 유지보수 악몽...

문제점:

  • ❌ 중복 코드: extract/transform 로직이 여러 스크립트에 흩어짐
  • ❌ 장애 전파: 한 ETL 실패하면 다음 작업까지 영향
  • ❌ 모니터링 어려움: 각 스크립트마다 로그 확인 필요
  • ❌ 확장성 없음: 새로운 데이터 소스 추가? → 또 새 스크립트 작성

문제 4: 재처리 불가능

상황: 어제 로그 처리 중 버그 발견
     결제 데이터는 잘못된 환율로 변환됨

AS-IS:
- 버그 수정 후 매일 자정까지 기다려야 함
- 그 사이 잘못된 데이터로 의사결정 → 손실 발생
- 수동으로 지난 데이터 재처리 → 복잡함

"지난주 데이터를 새로운 로직으로 다시 처리해줄 수 있나?"
→ 데이터 엔지니어: "손으로 쓰는 수밖에..."

문제 5: 서비스 간 비강력한 일관성 (Weak Consistency)

Timeline:
11:59 - [결제 서비스] 결제 처리 완료 (자체 DB에 저장)
12:00 - [ETL 시작] 결제 데이터 추출
12:30 - [Email 서비스] 자신의 스케줄로 별도 ETL 실행
        → "어제 고객이 뭘 샀지?" 데이터 필요
        → 근데 결제 DB 스키마 모르면? 또는 동기화 안 됐으면?

→ Email이 보내는 영수증 정보 ≠ 결제 정보
→ 고객 컴플레인 ("영수증에 잘못된 가격이...")

3. LinkedIn의 실제 문제

2010년 LinkedIn의 상황:
- 페이지뷰: 일일 수십억 건
- 회원 데이터: 계속 증가
- 각 팀이 필요한 데이터:
  * 마케팅: 회원 활동
  * 리크루팅: 직무 검색 패턴
  * 분석: 플랫폼 효율성
  
하지만:
→ 각 팀이 자신의 ETL을 따로 작성
→ 데이터 중복, 일관성 문제
→ 새벽에 배치 작업으로 서버 뻗음
→ "실시간" 데이터는 꿈

결론: 이대론 안 되겠다. 근본적인 인프라가 필요하다!

4. 당시 기존 메시지 큐의 한계

RabbitMQ, ActiveMQ 같은 전통적 메시지 큐도 있었지만, 데이터 파이프라인용으로는 부족했다:

Producer → [Message Queue] → Consumer
(메모리 기반)

문제점:
- 처리량: 일일 수십억 건 불가능 (대게 수천~수만 건/초)
- 내구성: 서버 재부팅 = 메시지 손실
- Replayability: 한번 처리한 메시지 다시 못 봄
- 저장 기간: 거의 실시간만 가능 (30일? 불가능)
- 확장성: 1대 큐 서버가 병목

→ "우리가 필요한 건 메시지 큐가 아니라, 분산 로그 시스템이다"

Kafka의 혁신: ETL을 무너뜨리다

1. 배치에서 실시간으로

Kafka의 설계 철학:

“데이터는 흐름(Stream)이다. 데이터를 모아뒀다가 한 번에 처리하지 말고, 계속 흘려보내자”

결제 완료 (오후 3시 15분)
  ↓ (즉시)
[Kafka Topic: payments] 
  ↓ (즉시)
- Email Consumer: 영수증 발송
- Analytics Consumer: 매출 집계
- Risk Consumer: 부정 거래 감지
- Data Lake Consumer: 원본 데이터 저장

→ 데이터 발생 = 즉시 여러 곳에서 활용 가능

효과:

AS-IS: 결제 → 21시간 뒤 → 분석
TO-BE: 결제 → 1초 이내 → 분석 (또는 실시간 제공)

2. 느슨한 결합: 한 곳에서 모든 데이터를 관리

[결제 시스템]
[로그 서버]      ┐
[고객 DB]   ───→ [Kafka Topics] ←─── 새로운 Consumer 추가해도 기존 시스템 무영향
[웹 분석]        ┘

각 Consumer는 독립적:
- Email Consumer가 장애? → 다른 Consumer는 계속 실행
- 새 분석팀: "우리도 결제 데이터 원해" → 새 Consumer 추가하면 끝
- 마케팅팀: "회원 활동 재분석해줄 수 있나?" → Offset 조정하면 과거 데이터부터 재처리

3. 배치의 비효율성 제거

배치 ETL의 문제:
- 자정마다 리소스 낭비
- 데이터 몰려도 대응 불가
- 하루에 1회만 처리

Kafka 기반 실시간 파이프라인:
- 데이터 발생하는 만큼만 리소스 사용
- 갑자기 트래픽 몰려? Consumer scale-out로 해결
- 24/7 처리 가능 (배치 개념 없음)

리소스 사용량 비교:
자정~4시: ████████████ (피크)
4시~자정: ░░░░░░░░░░░░ (유휴)
→ 비효율적

Kafka:
09:00 ██░░░░░░░░░ (낮지만 꾸준함)
15:00 ████████░░░ (트래픽 있을 때)
21:00 ██░░░░░░░░░ (정상)
→ 효율적

4. Replayability: 과거 데이터를 미래의 로직으로

상황: 신입 데이터 엔지니어가 집계 로직에 버그 만듦
      지난 30일간 잘못된 매출 집계 데이터 생성

AS-IS (배치 ETL):
"죄송합니다. 매출 데이터 30일치를 수동으로 다시 처리하는데 일주일 걸립니다"

TO-BE (Kafka):
버그 수정 후:
Consumer.seek(offset_from_30_days_ago)
→ 30일 데이터 자동 재처리 (몇 분 내 완료)

Kafka 전후: 데이터 파이프라인의 진화

측면 배치 ETL (Before) Kafka (After)
처리 방식 일일 1회 (자정) 실시간 스트림
데이터 지연 최대 24시간 밀리초 단위
리소스 효율 피크 시간에만 사용 24/7 균등 사용
재처리 수동, 복잡 자동, 오프셋으로 간단
Consumer 추가 새 ETL 스크립트 작성 Consumer 추가만으로 가능
장애 전파 ETL 하나 실패 → 종속 작업 무중단 한 Consumer 실패 → 다른 Consumer는 독립
모니터링 각 스크립트마다 로그 확인 중앙 Kafka 콘솔에서 전체 파악
데이터 보관 1~7일 설정에 따라 최대 365일

현실의 사례

AS-IS: 전통적인 배치 ETL 기반 이메일 발송

자정마다:
1. [결제 시스템] → 어제 결제 데이터 추출 (1시간)
2. → [데이터웨어하우스]에 로드 (30분)
3. → 데이터 정제 (30분)
4. → [이메일 시스템]에 전달 (30분)
5. 새벽 3시: 어제 고객들에게 영수증 이메일 발송

문제:
- 결제한 지 24시간이 지난 후에야 이메일 발송
- 결제 직후 영수증을 바로 받고 싶어? 불가능
- 아침에 결제했는데 자정까지 기다려야 함

TO-BE: Kafka 기반 실시간 파이프라인

1. 결제 완료 (오후 3시 15분)
   ↓
2. 결제 시스템이 "payments" 토픽에 이벤트 발행
   ↓
3. Email Consumer: 즉시 이메일 발송 (3:15 + 10초 = 3:15:10)
   Analytics Consumer: 실시간 매출 대시보드 업데이트
   Fraud Consumer: 부정 거래 감지
   Data Lake Consumer: 원본 저장

효과:
- 고객: 결제 후 1분 내 영수증 받음 (만족도 ↑)
- 마케팅: 실시간으로 매출 추이 파악 (의사결정 빨라짐)
- 리스크팀: 부정거래 실시간 감지 (손실 최소화)

문제 상황에서의 대응 비교

상황: 결제 데이터의 통화 환율 계산에 버그 발견

AS-IS (배치):
Day 1 아침: "어제 데이터에 오류 발견!"
Day 1 오후: 개발자가 코드 수정
Day 2 자정: 다음 배치 실행 (자동으로 수정됨)
결과: 1.5일간 잘못된 데이터로 의사결정

TO-BE (Kafka):
Now: "방금 버그 발견!"
Now + 5분: 개발자가 코드 수정, 배포 완료
Now + 10분: 개발자가 Consumer를 30분 전부터 재시작
         ("offset을 30분 전으로 seek")
결과: 30분 안에 모든 데이터 재처리 완료

마치며

Kafka의 등장은 단순한 기술 개선이 아니라, 데이터 처리 패러다임 자체의 전환이었다:

  • 🚫 배치에서 스트림으로: 하루 1회 → 24/7 실시간
  • 🔗 강한 결합에서 느슨한 결합으로: 각 ETL 독립 → 중앙 토픽 기반
  • ⏮️ 일회성에서 재연생 가능으로: 한번 처리하면 끝 → 언제든 재처리 가능
  • 📊 작은 데이터에서 빅데이터로: 수백만 건/일 → 수조 건/일

LinkedIn에서 시작된 Kafka는 이제:

  • Netflix, Uber, Airbnb: 실시간 데이터 처리
  • 금융권: 주식거래 실시간 분석
  • IoT: 수십억 센서 데이터 수집

오늘날 “실시간 데이터 기반 의사결정”이 당연한 세상이 된 것은, Kafka가 전통적 ETL의 비효율을 정면으로 마주하고 근본적으로 해결했기 때문이다.


더 읽을거리: