📗Spark on Kubernetes 개요
Spark on Kubernetes는 Apache Spark 애플리케이션을 Kubernetes 클러스터 위에서 직접 실행하는 방법을 말한다. Spark Driver와 Spark Executor가 Kubernetes의 Pod로 실행된다. Kubernetes가 자원 할당, 스케줄링, 격리(아이솔레이션)를 관리한다. Spark는 Kubernetes를 하나의 클러스터 매니저(cluster manager)처럼 사용한다.
주요 특징
- 탄력성: 필요에 따라 Executor 수를 늘리거나 축소 가능 (Dynamic Allocation 가능).
- 자원 격리: Kubernetes 네이티브 기능(CPU/MEM 요청, 제한 등)을 활용 가능.
- 스토리지: S3, HDFS, PVC(PersistentVolumeClaim) 등 Kubernetes 스토리지 시스템 사용 가능
- 네트워킹: Kubernetes CNI (예: Cilium, Calico)를 통해 Pod 간 통신.
🏳️🌈 [궁금한점]
목차
| 구성 요소 | 역할 |
|---|---|
| Driver Pod | Spark 애플리케이션의 메인 프로세스 (Job 스케줄링, Task 분배) |
| Executor Pods | 실질적으로 Task를 실행하는 작업자들 |
| Kubernetes API Server | Spark가 리소스를 요청하고 관리하는 대상 |
전통적인 YARN 기반 대신에 Kubernetes 위에 직접 Spark를 구동하는 식으로 전환되고 있다. 아래와 같은 이유로 신규 프로젝트는 Kubernetes 위에서 Spark를 돌리려는 흐름이다.
Spark 클러스터를 직접 운영하지 않고, 필요할 때만 Spark 세션을 만드는 서비스가 인기다.
Spark를 단순한 ETL 도구로 쓰는게 아니라, Iceberg, Delta 같은 테이블 포맷을 읽고 쓰는 레이크하우스(Lakehouse) 아키텍처에 통합해서 사용한다. Spark가 S3 같은 오브젝트 스토리지 위의 데이터를 직접 처리하는 게 일반적이다.
과거에는 Java/Scala가 기본이었지만, 최근에는 PySpark가 훨씬 더 많이 쓰인다. 특히 Data Scientist나 ML 엔지니어들이 Python 기반 워크플로우를 선호한다. 그로 인해 Spark 3.x 이후로 Python API 최적화(Arrow 연동, UDF 성능 향상)가 엄청 진행 되었다.
Kubernetes + Spark 환경에서는 Executor 수를 자동 조정(Dynamic Allocation)하고, Executor 스펙(CPU/MEM)을 런타임에 최적화한다. Spot/Preemptible 인스턴스를 적극 활용한다. "얼마나 빠르게 처리하냐"보다 "얼마나 싸게 처리하냐"가 더 중요한 포인트가 되었다.
스파크의 "완전히 대체" 라기보다는,
"특정 상황에서 더 나은 대안" 을 지향하는 흐름이다.
Spark가 Batch 처리에 강하다면, Ray는 Batch + Streaming + ML workload를 다 하나로 통합할 수 있다. "Spark는 느려, 복잡해" -> "Ray로 빠르고 심플하게 가자" 이런 흐름이 일부 있다.
특징:
Spark Streaming 대신 Flink를 쓰는 경우가 점점 늘고 있다.
Flink는 네이티브 스트리밍(Native Streaming) 엔진이고,
Spark는 Micro-batch 기반 Streaming이라 기능에 차이가 있다.
Flink도 Kubernetes에 완전 최적화돼 있다. "실시간 처리는 Spark 말고 Flink로 하자"는 흐름이 강하다.
Spark를 "작업 스케줄러" 기능을 워크플로 전용 툴(Dagster, Prefect, Airflow)로 빼고, Spark는 오직 "데이터 처리"에만 집중시키는 식으로 가고 있다.
Kubernetes, Spark 둘 다 없이,
SaaS 기반 DWH나 Lakehouse를 쓰는 흐름도 점점 커지고 있다. 인프라 관리를 안 해도 되고 SQL 쓰면 되니 접근성이 좋다.
Spark on Kubernetes 환경에서 Executor는 Spark 애플리케이션 실행 시 실제 작업(Task)을 수행하는 핵심 구성 요소이다.
Spark 애플리케이션은 Driver와 여러 개의 Executor로 구성된다. Driver는 작업을 계획하고 Executor에게 Task를 분배한다. Executor는 데이터를 처리하고 결과를 Driver에게 반환한다.
--executor-memory 4g
--executor-cores 2
--conf spark.executor.instances=3
--conf spark.kubernetes.container.image=<이미지>
Spark에서 Task, Partition, Executor의 관계는 Spark의 병렬 처리 구조를 이해하는 데 핵심이다.
| 개념 | 설명 |
|---|---|
| Partition | RDD/DataFrame을 나눈 논리적 조각. 각 파티션은 독립적으로 처리될 수 있음. |
| Task | 하나의 Partition을 처리하는 단위 작업. 즉, 1 Task = 1 Partition 처리 |
| Executor | Task를 실제 실행하는 Spark의 작업자 프로세스. Driver에 의해 명령을 받아 Task 실행 |
Executor가 여러 Task를 실행하게 되며, 각 Task는 하나의 Partition을 처리한다.
관련 설정들
- --executor-cores: Executor 하나당 동시에 실행할 수 있는 Task 수
- --num-executors: Executor 개수
- --spark.sql.shuffle.partitions: shuffle 이후 파티션 수 (→ Task 수에 영향)