대규모 데이터 처리 엔진을 선택할 때, Flink와 Spark는 가장 자주 비교되는 두 기술이다. 둘 다 분산 데이터 처리를 지원하지만, 태생과 철학이 다르다. Spark는 배치에서 시작하여 스트리밍으로 확장했고, Flink는 스트리밍에서 시작하여 배치를 지원한다. 이 차이가 아키텍처 전반에 영향을 미친다.
아키텍처 철학
Spark: 배치 우선
Spark의 핵심 추상화는 RDD(Resilient Distributed Dataset) 이다. 불변의 분산 데이터셋을 변환하는 배치 처리 모델이다. Spark Structured Streaming은 이 배치 엔진 위에 마이크로배치를 반복 실행하여 스트리밍을 구현한다.
입력 스트림: ──────────────────────────→
마이크로배치: |--batch--|--batch--|--batch--|
각 배치: 독립적인 Spark 잡으로 실행
Flink: 스트리밍 우선
Flink의 핵심은 연속적인 이벤트 처리이다. 데이터가 하나씩 도착할 때마다 처리하는 네이티브 스트리밍 엔진이다. 배치는 "유한한 스트림"의 특수한 경우로 취급한다.
입력 스트림: ──event──event──event──event──→
처리: 각 이벤트를 즉시 처리
이 철학적 차이가 성능, API, 상태 관리 등 모든 측면에 영향을 미친다.
스트리밍 처리 비교
지연 시간(Latency)
| Spark Structured Streaming | Flink | |
|---|---|---|
| 처리 모델 | 마이크로배치 | 네이티브 스트리밍 |
| 최소 지연 | 수백 밀리초 ~ 초 | 밀리초 |
| 트리거 간격 | 설정 가능 (기본 수백ms) | 이벤트 단위 |
Spark의 마이크로배치는 짧은 간격의 배치를 반복하는 것이므로, 아무리 간격을 줄여도 진정한 이벤트 단위 처리는 불가능하다. Flink는 이벤트가 도착하는 즉시 처리한다.
밀리초 단위의 지연이 중요한 경우(사기 거래 탐지, 실시간 경매 등) Flink가 적합하다. 초 단위 지연이 허용되는 경우 Spark도 충분하다.
이벤트 타임 처리
이벤트 발생 시각: 10:00:01 10:00:02 10:00:03
도착 시각: 10:00:03 10:00:01 10:00:05 (순서 뒤바뀜)
실세계에서 이벤트는 발생 순서대로 도착하지 않는다. 네트워크 지연, 모바일 오프라인 등으로 순서가 뒤바뀌거나 늦게 도착한다.
Flink: Watermark 메커니즘이 성숙하다. 이벤트 타임 기반 윈도우, 늦은 데이터 처리, Side Output 등을 세밀하게 제어할 수 있다.
Spark: Structured Streaming도 Watermark를 지원하지만, 마이크로배치 경계에서 처리되므로 Flink만큼 세밀한 제어는 어렵다.
윈도우 연산
| 윈도우 유형 | Spark | Flink |
|---|---|---|
| Tumbling Window | O | O |
| Sliding Window | O | O |
| Session Window | O | O |
| Global Window | X | O |
| 커스텀 Trigger | 제한적 | 완전 지원 |
| 늦은 데이터 처리 | Watermark + Drop | Watermark + Side Output + Allowed Lateness |
Flink는 커스텀 Trigger와 Evictor로 윈도우 동작을 완전히 제어할 수 있다. Spark는 기본 제공 윈도우로 대부분의 경우를 커버하지만, 고급 커스터마이징은 제한적이다.
배치 처리 비교
성숙도와 에코시스템
Spark은 배치 처리의 사실상 표준이다. 10년 이상 검증되었고, 에코시스템이 방대하다.
- Spark SQL: 강력한 SQL 엔진, Catalyst 옵티마이저
- MLlib: 분산 머신러닝 라이브러리
- GraphX: 그래프 처리
- DataFrame/Dataset API: 풍부한 데이터 변환 API
- 다양한 커넥터: JDBC, Hive, S3, Delta Lake, Iceberg 등
Flink의 배치 지원은 빠르게 발전하고 있지만, Spark만큼의 에코시스템은 아직 갖추지 못했다.
- Table API/SQL: SQL 지원은 양호하지만 Spark SQL만큼 성숙하지 않음
- ML 라이브러리: 제한적 (실무에서는 거의 사용 안 됨)
- 커넥터: 주요 커넥터는 있지만 Spark보다 적음
배치 성능
순수 배치 성능만 비교하면, Spark의 Adaptive Query Execution(AQE), Catalyst 옵티마이저, Columnar Processing 등이 잘 최적화되어 있다. 대용량 ETL에서 Spark가 더 효율적인 경우가 많다.
Flink 배치 모드는 Blocking Shuffle, 스테이지 기반 스케줄링 등 배치 최적화를 적용하지만, Spark의 배치 최적화 역사에 비하면 아직 발전 여지가 있다.
상태 관리(State Management)
Flink의 상태 관리
Flink는 상태를 1등 시민(first-class citizen) 으로 취급한다.
┌────────────────────────┐
│ Flink Task │
│ ├── Keyed State │ ← 키별 상태 (ValueState, MapState 등)
│ ├── Operator State │ ← 연산자별 상태
│ └── RocksDB Backend │ ← 디스크 기반, 대용량 상태 지원
└────────────────────────┘
↓ Checkpoint
[분산 스토리지에 스냅샷 저장]
- Keyed State: 키별로 독립된 상태를 관리. ValueState, ListState, MapState 등 풍부한 상태 타입
- State Backend: 메모리(HashMapStateBackend) 또는 디스크(EmbeddedRocksDBStateBackend) 선택
- Checkpoint: 주기적으로 전체 상태를 일관되게 스냅샷
- Savepoint: 수동으로 생성하는 스냅샷. 잡 업데이트, 스케일링에 사용
Flink는 수 테라바이트의 상태도 안정적으로 관리할 수 있다.
Spark의 상태 관리
Spark Structured Streaming도 상태 기반 연산을 지원한다.
# mapGroupsWithState: 커스텀 상태 관리
def update_state(key, values, state):
# state.get(), state.update(), state.remove()
pass
df.groupByKey(lambda x: x.user_id) \
.mapGroupsWithState(update_state, ...)
하지만 Flink에 비해 제약이 있다:
- 상태 타입이 제한적이다
- 대용량 상태에서의 성능이 Flink보다 떨어질 수 있다
- 상태 백엔드 옵션이 적다
- Savepoint 같은 상태 마이그레이션 도구가 부족하다
상태가 복잡하고 대용량인 스트리밍 애플리케이션에서는 Flink가 명확히 우위이다.
Exactly-once 보장
Flink
Checkpoint + Two-Phase Commit으로 End-to-End Exactly-once를 보장한다.
Source(Kafka) → Flink(Checkpoint) → Sink(Kafka 트랜잭션)
offset 저장 상태 스냅샷 트랜잭션 커밋
└─────── 하나의 Checkpoint에서 원자적으로 ───────┘
Spark
Structured Streaming은 마이크로배치의 멱등 쓰기와 WAL(Write-Ahead Log) 로 Exactly-once를 보장한다.
마이크로배치 N: [읽기 offset 기록] → [처리] → [멱등 쓰기] → [offset 커밋]
두 엔진 모두 Exactly-once를 달성하지만, 메커니즘이 다르다. Flink는 분산 스냅샷(Chandy-Lamport) 기반이고, Spark는 마이크로배치 재실행 기반이다.
운영(Operations)
배포와 관리
| Spark | Flink | |
|---|---|---|
| 클러스터 관리자 | YARN, Mesos, K8s, Standalone | YARN, K8s, Standalone |
| 관리형 서비스 | EMR, Databricks, GCP Dataproc | AWS KDA, Ververica Platform |
| 커뮤니티 크기 | 매우 큼 | 성장 중 |
| 인력 채용 | 상대적으로 용이 | 상대적으로 어려움 |
| 문서/자료 | 풍부 | 양호하지만 Spark보다 적음 |
모니터링
- Spark: Spark UI, History Server. 잡/스테이지/태스크별 상세 메트릭
- Flink: Flink Dashboard. 실시간 처리량, 지연, Checkpoint 상태, 백프레셔 지표
잡 업데이트
Flink: Savepoint를 생성하고, 새 버전의 잡을 Savepoint에서 복구하여 상태를 유지한 채 업데이트할 수 있다. 이는 Flink의 큰 장점이다.
Spark: Structured Streaming 잡을 중지하고 새 버전을 시작한다. Checkpoint에서 복구되지만, 코드 변경 범위에 따라 호환성 문제가 발생할 수 있다.
선택 가이드
Flink를 선택해야 하는 경우
- 밀리초 단위 지연이 필요한 실시간 처리
- 대용량 상태 관리가 필요한 스트리밍 애플리케이션
- 복잡한 이벤트 처리(CEP)가 핵심 요구사항
- 이벤트 타임 처리가 정교하게 필요한 경우
- 배치와 스트리밍 코드를 통합하고 싶은 경우
Spark를 선택해야 하는 경우
- 대규모 배치 ETL이 주 워크로드
- ML 파이프라인을 데이터 처리와 함께 구축
- SQL 중심의 데이터 분석이 필요한 경우
- 풍부한 에코시스템과 커뮤니티 지원이 중요한 경우
- 초 단위 지연이 허용되는 스트리밍
둘 다 사용하는 경우
실무에서는 두 엔진을 함께 사용하는 것이 드물지 않다.
[실시간 경로]
Kafka → Flink → Redis/Elasticsearch (실시간 대시보드, 알림)
[배치 경로]
S3 → Spark → Data Warehouse (일별 집계, ML 학습, 리포트)
실시간 이벤트 처리는 Flink로, 대규모 배치 분석과 ML은 Spark로 처리하는 것이 각 엔진의 강점을 살리는 방식이다.
정리
| 관점 | Flink | Spark |
|---|---|---|
| 스트리밍 | 네이티브, 밀리초 지연 | 마이크로배치, 초 단위 지연 |
| 배치 | 지원하나 발전 중 | 사실상 표준, 매우 성숙 |
| 상태 관리 | 매우 강력 (TB급 상태) | 기본적 지원 |
| 에코시스템 | 스트리밍 중심 | 배치/ML/SQL 모두 풍부 |
| 운영 | Savepoint로 무중단 업데이트 | 대규모 커뮤니티와 자료 |
- "하나가 다른 하나보다 무조건 낫다"가 아니다. 워크로드에 맞는 도구를 선택하는 것이 핵심이다
- 실시간 스트리밍이 핵심이면 Flink, 배치 분석과 ML이 핵심이면 Spark
- 두 워크로드가 모두 중요하면, 각각의 강점을 살려 병행하는 것이 실무적 선택이다