LLM WikiAccess-protected knowledge portal
← 스터디 홈
1편 · 약 13분

Apache Spark 아키텍처와 핵심 개념

MapReduce의 한계와 Spark의 탄생

2004년 Google이 MapReduce를 발표하고 Apache Hadoop이 이를 오픈소스로 구현하면서 수십 테라바이트 규모의 배치 처리가 가능해졌다. 그러나 Hadoop MapReduce에는 구조적인 한계가 있었다. 중간 결과를 매번 HDFS에 쓰고 읽어야 했기 때문에 반복 알고리즘(머신러닝, 그래프 연산)에서는 I/O 비용이 누적되어 느렸다. 또한 각 작업을 별도 MapReduce 잡으로 표현해야 했기에 복잡한 파이프라인을 직관적으로 작성하기 어려웠다.

Apache Spark는 2009년 UC Berkeley AMPLab에서 이 문제를 해결하기 위해 시작됐다. 핵심 아이디어는 두 가지다. 첫째, 중간 데이터를 HDFS 대신 메모리에 캐시한다. 둘째, 일련의 변환을 DAG(방향성 비순환 그래프)로 표현해 한 번에 최적화한다. 현재는 Apache Software Foundation 최상위 프로젝트로, 배치·스트리밍·SQL·머신러닝을 단일 엔진에서 처리하는 표준 빅데이터 플랫폼이 됐다.

클러스터 아키텍처: Driver · Cluster Manager · Executor

Spark 애플리케이션은 세 가지 프로세스로 구성된다.

사용자 코드 spark-submit Driver Process SparkContext / SparkSession DAG Scheduler + Task Scheduler Cluster Manager YARN / Kubernetes / Standalone Executor 1 (Worker) Task 1 Task 2 캐시 (RDD/DF) Executor 2 (Worker) Task 3 Task 4 캐시 (RDD/DF) Executor 3 (Worker) Task 5 Task 6 캐시 (RDD/DF) 태스크 배포
Spark 클러스터 아키텍처: Driver, Cluster Manager, Executors

Driver는 애플리케이션의 두뇌다. SparkSession(또는 SparkContext)을 생성하고, 사용자 코드를 DAG로 변환해 스케줄링한다. Driver는 Executor의 태스크 완료 상태를 추적하고 실패 시 재시도를 지시한다. Driver가 죽으면 애플리케이션 전체가 종료된다.

Cluster Manager는 클러스터 자원을 할당한다. Spark 자체 Standalone 모드, Apache YARN(Hadoop 생태계), Kubernetes를 지원한다. Cluster Manager는 Spark를 모른다—단지 컨테이너(CPU/메모리)를 Executor에 제공할 뿐이다.

Executor는 실제 데이터를 처리하는 JVM 프로세스다. 할당된 CPU 코어 수만큼 태스크를 병렬 실행하고, 캐시 데이터를 메모리(또는 디스크)에 저장한다. Executor는 애플리케이션이 살아있는 동안 고정적으로 실행된다(동적 할당 기능 제외).

RDD: Spark의 기본 데이터 모델

RDD(Resilient Distributed Dataset)는 Spark의 근본 추상화다. 세 가지 특성을 가진다.

  • 분산(Distributed): 파티션으로 나뉘어 여러 Executor에 분산 저장된다.
  • 불변(Immutable): 한번 생성된 RDD는 수정되지 않는다. 변환(transformation)은 항상 새 RDD를 반환한다.
  • 내구성(Resilient): 파티션 계보(lineage) 정보를 통해 Executor 장애 시 해당 파티션만 재계산할 수 있다.

그러나 RDD는 타입 안전성은 있지만 Catalyst 옵티마이저를 거치지 않기 때문에, 현대 Spark에서는 구조적 API인 DataFrameDataset을 사용한다. DataFrame은 Named Column이 있는 분산 테이블(Python/R)이고, Dataset은 JVM 타입 안전성을 더한 DataFrame(Scala/Java)이다.

Lazy Evaluation과 DAG

Spark의 모든 변환(transformation)(예: filter, map, join, groupBy)은 지연 실행(lazy)이다. 변환을 호출해도 즉시 실행되지 않고, DAG 계획에 추가만 된다. 실제 계산은 액션(action)(예: count, show, write, collect)이 호출될 때 시작된다.

read CSV → (변환) filter(age > 20) → (변환) groupBy(city) → (변환) count() → (액션!) 실행 시작
변환 3개: DAG에 기록만 됨 Catalyst가 DAG 최적화 Physical Plan → Task 분배
Lazy Evaluation: 변환은 DAG에 쌓이고, 액션에서만 실행된다

지연 실행의 장점은 최적화다. Catalyst 옵티마이저가 전체 계획을 보고 불필요한 컬럼 제거(projection pushdown), 필터를 데이터 소스 쪽으로 밀어내기(predicate pushdown), 조인 순서 재배치 등을 자동으로 수행한다.

Job → Stage → Task: 실행 단위 계층

액션이 호출되면 Spark는 DAG를 분석해 Job → Stage → Task 계층으로 분해한다.

단위정의생성 조건
Job하나의 액션이 트리거하는 전체 DAG 실행액션 호출마다 1개
Stage셔플 없이 연속 실행 가능한 태스크 묶음Wide dependency마다 경계 생성
Task단일 파티션에 대한 단일 Stage 연산파티션 수만큼 병렬 생성

Narrow dependency(예: map, filter)는 입력 파티션 1개가 출력 파티션 1개에만 영향을 준다. 같은 Stage에서 파이프라인으로 처리된다. Wide dependency(예: groupByKey, join, repartition)는 여러 파티션의 데이터가 섞여야 한다. 이 셔플(shuffle) 경계에서 새 Stage가 생성된다.

셔플은 네트워크를 통해 데이터를 재분배하므로 가장 비싼 연산이다. 셔플 데이터는 디스크에 임시로 쓰이고 다음 Stage가 읽어간다. 실무에서는 셔플 수를 줄이는 것이 Spark 성능 최적화의 핵심이다.

Spark 구성요소 전체 그림

Spark SQL / DataFrame Spark Streaming (구조적) MLlib (머신러닝) GraphX (그래프)
Spark Core (RDD / DAG Scheduler / Task Scheduler)
Catalyst 옵티마이저 + Tungsten 실행 엔진
YARN Kubernetes Standalone HDFS / S3 / GCS
Spark 에코시스템: 단일 엔진 위의 다중 워크로드

Spark는 라이브러리 수준에서 SQL, 스트리밍, 머신러닝, 그래프 연산을 통합한다. 데이터 레이크(S3, HDFS, GCS)를 직접 읽고, Iceberg·Delta Lake·Hudi 같은 오픈 테이블 포맷과 결합해 Lakehouse 아키텍처의 처리 엔진으로도 널리 쓰인다.

한 줄 정리

Apache Spark는 DAG 기반 지연 실행과 인메모리 캐싱으로 Hadoop MapReduce의 반복 I/O 문제를 해결한 분산 처리 엔진이며, Driver·Executor 구조와 Job→Stage→Task 계층으로 배치·스트리밍·ML을 단일 플랫폼에서 처리한다.

References

  • https://medium.com/@vigneshbw2002/understanding-apache-spark-architecture-driver-executors-cores-partitions-stages-and-shuffles-e6893db16994
  • https://medium.com/@mohanaslvn/spark-architecture-explained-dag-executors-stages-tasks-simplified-80e46b9989fa
  • https://reintech.io/blog/optimizing-spark-data-transformations
  • https://shreyash27.hashnode.dev/understanding-the-spark-execution-model
  • https://luminousmen.com/post/spark-anatomy-of-spark-application/
  • https://www.xenonstack.com/blog/rdd-in-spark/