데이터 파이프라인을 설계할 때 가장 먼저 결정해야 하는 것은 "데이터를 언제 처리할 것인가?" 이다. 하루치 데이터를 모아서 한 번에 처리할 것인가(배치), 아니면 데이터가 들어오는 즉시 처리할 것인가(스트리밍). 이 선택이 전체 아키텍처의 기반을 결정한다.
배치 처리(Batch Processing)
개념
일정 시간 동안 축적된 데이터를 한꺼번에 처리하는 방식이다. 전통적인 데이터 처리 모델이며, 대부분의 데이터 웨어하우스와 ETL 파이프라인이 이 방식을 따른다.
[데이터 축적] → [스케줄 트리거] → [일괄 처리] → [결과 저장]
대표적인 배치 처리 도구:
- Apache Spark: 대용량 분산 배치 처리의 사실상 표준
- Apache Hive: Hadoop 위의 SQL 기반 배치 처리
- Apache Airflow: 배치 워크플로우 오케스트레이션
- dbt: SQL 기반 데이터 변환
특징
장점:
- 높은 처리량: 데이터를 모아서 처리하므로 I/O 오버헤드가 적다
- 단순한 로직: 전체 데이터를 대상으로 처리하므로 로직이 직관적이다
- 비용 효율: 필요한 시간에만 리소스를 사용하고 반납할 수 있다
- 재처리 용이: 문제가 발생하면 같은 입력으로 다시 실행하면 된다
한계:
- 높은 지연: 데이터 발생부터 결과 반영까지 시간(분~시간)이 걸린다
- 리소스 피크: 처리 시점에 대량의 리소스가 집중적으로 필요하다
적합한 유스케이스
- 일일/주간/월간 리포트 생성
- 대규모 데이터 ETL
- 머신러닝 모델 학습
- 데이터 웨어하우스 적재
스트리밍 처리(Stream Processing)
개념
데이터가 발생하는 즉시 연속적으로 처리하는 방식이다. 이벤트 하나하나를 실시간으로 처리하거나, 짧은 시간 윈도우(마이크로배치) 단위로 처리한다.
[이벤트 발생] → [즉시 수집] → [실시간 처리] → [결과 반영]
대표적인 스트리밍 처리 도구:
- Apache Flink: 네이티브 스트리밍 처리 엔진
- Apache Kafka Streams: Kafka 기반 경량 스트림 처리
- Apache Spark Structured Streaming: Spark의 마이크로배치 스트리밍
특징
장점:
- 낮은 지연: 이벤트 발생 후 밀리초~초 단위로 결과를 얻을 수 있다
- 실시간 인사이트: 현재 상황을 즉시 파악하고 대응할 수 있다
- 균일한 리소스 사용: 처리가 지속적으로 분산되어 피크가 적다
한계:
- 복잡한 로직: 순서 보장, 지연 도착, 상태 관리 등 고려할 사항이 많다
- 정확성 보장 어려움: Exactly-once 처리를 위한 추가 메커니즘이 필요하다
- 상시 운영 비용: 24시간 클러스터를 유지해야 한다
- 디버깅 난이도: 시간 순서에 따른 비결정적 동작으로 재현이 어렵다
적합한 유스케이스
- 실시간 이상 탐지 (사기 거래, 장애 감지)
- 실시간 대시보드와 모니터링
- IoT 센서 데이터 처리
- 실시간 추천/개인화
- CDC 기반 데이터 동기화
마이크로배치: 중간 지대
마이크로배치(Micro-batch) 는 짧은 시간 간격(수 초)으로 작은 배치를 반복 실행하는 방식이다. 배치와 스트리밍의 중간에 위치한다.
Spark Structured Streaming이 대표적이다. 내부적으로는 짧은 주기의 배치 잡을 반복 실행하지만, 프로그래밍 모델은 스트리밍처럼 보인다.
|--batch--|--batch--|--batch--|--batch--| → Micro-batch (Spark)
|event|event|event|event|event|event| → Native Streaming (Flink)
마이크로배치는 배치 엔진의 안정성과 스트리밍의 낮은 지연을 절충한다. 다만, 진정한 이벤트 단위 처리가 필요한 경우에는 Flink 같은 네이티브 스트리밍 엔진이 적합하다.
Lambda 아키텍처
설계 원리
Lambda 아키텍처는 배치와 스트리밍을 동시에 운영하여 각각의 장점을 취하는 방식이다. Nathan Marz가 제안했다.
┌──[Batch Layer]──→ Batch View ─┐
데이터 소스 → 수집 →│ ├→ Serving Layer → 쿼리
└──[Speed Layer]──→ Real-time View─┘
세 개의 레이어로 구성된다.
Batch Layer: 전체 데이터를 주기적으로 처리하여 정확한 결과를 생성한다. 처리 시간은 길지만 결과가 정확하다.
Speed Layer: 마지막 배치 이후의 데이터를 실시간으로 처리하여 최신 결과를 생성한다. 근사치일 수 있지만 빠르다.
Serving Layer: 두 레이어의 결과를 병합하여 쿼리에 응답한다. 배치 결과(정확) + 실시간 결과(최신)를 합쳐 완전한 뷰를 제공한다.
구현 예시
Batch Layer: Kafka → S3 → Spark(일별) → Data Warehouse
Speed Layer: Kafka → Flink(실시간) → Redis
Serving: Query → [Warehouse 결과] + [Redis 결과] 병합
문제점
Lambda 아키텍처의 가장 큰 문제는 동일한 비즈니스 로직을 두 번 구현해야 한다는 점이다. 배치용 Spark 코드와 스트리밍용 Flink 코드가 같은 결과를 내도록 유지해야 한다. 코드가 두 벌이니 버그도 두 곳에서 발생하고, 결과의 일관성을 보장하기 어렵다.
Kappa 아키텍처
설계 원리
Kappa 아키텍처는 Jay Kreps(LinkedIn, Kafka 창시자)가 제안한 방식으로, 스트리밍 레이어만으로 배치와 실시간 처리를 모두 해결한다.
데이터 소스 → Kafka(이벤트 로그) → Stream Processor → Serving Layer → 쿼리
핵심 아이디어는 두 가지이다.
- 모든 데이터를 이벤트 로그(Kafka)에 보존한다. Kafka의 Retention을 충분히 길게(또는 무한) 설정한다.
- 재처리가 필요하면 로그를 처음부터 다시 읽는다. 새로운 스트리밍 잡을 배포하고, Kafka의 처음부터 다시 소비하면 배치 처리와 동일한 효과를 얻는다.
구현 예시
데이터 소스 → Kafka(장기 보존) → Flink → Elasticsearch/DB
↑
재처리: 새 잡을 배포하고 offset을 처음으로
Lambda vs Kappa 비교
| 특성 | Lambda | Kappa |
|---|---|---|
| 로직 구현 | 배치 + 스트리밍 2벌 | 스트리밍 1벌 |
| 운영 복잡도 | 높음 (두 시스템 관리) | 낮음 (하나의 시스템) |
| 재처리 방식 | 배치 레이어가 담당 | Kafka 로그 재소비 |
| 정확성 | 배치가 보정 | 스트리밍 정확성에 의존 |
| 적합한 경우 | 레거시 배치 시스템 존재 시 | 신규 구축, 이벤트 소싱 |
Kappa가 더 단순하지만, 모든 상황에 적합한 것은 아니다. 대규모 히스토리컬 데이터를 복잡한 SQL로 분석해야 하는 경우, 배치 엔진이 더 효율적이다. 실무에서는 두 아키텍처를 순수하게 적용하기보다 하이브리드 방식이 많다.
선택 기준
어떤 처리 방식을 선택할 것인가?
결정의 핵심은 지연 요구사항과 데이터 볼륨이다.
| 질문 | 배치 | 스트리밍 |
|---|---|---|
| 결과가 몇 분 늦어도 되는가? | O | X |
| 이벤트 단위 즉시 반응이 필요한가? | X | O |
| 데이터 볼륨이 매우 큰가? | 유리 | 가능하지만 비용↑ |
| 로직이 복잡한 조인/집계인가? | 유리 | 가능하지만 난이도↑ |
| 24시간 상시 운영이 가능한가? | 불필요 | 필수 |
실무에서의 조합
현실의 데이터 플랫폼은 대부분 배치와 스트리밍을 함께 사용한다.
[실시간 경로]
사용자 이벤트 → Kafka → Flink → Redis(실시간 대시보드)
↓
[배치 경로]
→ S3 → Spark(일별) → Data Warehouse(리포트)
실시간 대시보드는 Flink로, 일별 리포트와 심층 분석은 Spark로 처리하는 것이 전형적인 패턴이다. 중요한 것은 하나의 아키텍처에 집착하지 않고, 유스케이스에 맞는 처리 방식을 선택하는 것이다.
정리
- 배치 처리는 높은 처리량과 단순한 로직이 장점이지만 지연이 크다
- 스트리밍 처리는 실시간 반응이 가능하지만 복잡도와 운영 비용이 높다
- Lambda 아키텍처는 배치+스트리밍을 병행하지만, 로직 이중 구현이 문제다
- Kappa 아키텍처는 스트리밍만으로 통합하여 단순성을 확보한다
- 실무에서는 유스케이스별로 배치와 스트리밍을 적절히 조합하는 것이 일반적이다