어두운 작전 회의실의 원형 전투 지도 앞에서 다음 정복 대상을 정하는 오크 전쟁 회의

⚔️ 전쟁 회의 — 다음 정복 대상 선정

Spark Essential Curriculum

📖 시리즈: Spark-Essential (1 / 1)
Spark Essential — Driver/Executor 실행 구조와 7단계 도장깨기 로드맵 SPARK ESSENTIAL 실행 구조 — Driver가 세우고, Executor가 나눠 수행하고, 셔플로 다시 모은다 Driver DAG 수립 · 분배 Executor Executor Executor task 수행 셔플 · 키 재배치 결과 집계·조인 완료 7단계 로드맵 — 기반 → 성능 → 활용, 그리고 완주 기반 (1–3) 성능 (4) 활용 (5–7) 1 아키텍처 2 추상화 3 옵티마이저 4 셔플·튜닝 5 스트리밍 6 PySpark 7 레이크하우스 완주
이 시리즈를 한 장으로 — Spark 실행 구조(Driver·Executor·셔플)와 아키텍처부터 레이크하우스까지 7단계 도장깨기 로드맵, 그리고 완주 트로피

소개

Data-Engineering-Essential 오버뷰 시리즈는 데이터 엔지니어링 수명주기 전체의 지도를 그렸습니다. 그 5단계 데이터 변환·처리(Processing)에서 우리는 분산 처리가 왜 MapReduce에서 Apache Spark로 넘어왔는지, Driver/Executor 구조와 lazy evaluation의 큰 틀을 짚었습니다. 다만 거기서는 “처리 지도 안에서 Spark가 어디에 있는가”까지만 다루고, 구조·튜닝·API의 깊은 이야기는 별도 시리즈로 미뤄 두었습니다. 이 글이 바로 그 예고된 스핀오프, Spark-Essential 시리즈의 마스터 로드맵입니다.

Apache Spark는 2026년 현재도 대규모 분산 처리의 사실상 표준입니다. 데이터 엔지니어 채용에서 가장 높은 수요를 차지하는 처리 프레임워크이자, 배치·스트리밍·머신러닝을 하나의 엔진으로 아우르는 기반 기술입니다. 그런데 Spark를 “돌아가게” 만드는 것과 “빠르고 안정적으로” 만드는 것은 전혀 다른 문제입니다. 후자는 내부 구조 — 실행이 어떻게 스테이지로 쪼개지고, 셔플이 어디서 일어나며, 옵티마이저가 무엇을 바꾸는지 — 를 이해해야 비로소 손에 잡힙니다.

이 시리즈는 그 내부로 들어갑니다. 아키텍처(무엇이 어떻게 실행되는가)에서 출발해, 핵심 추상화(RDD/DataFrame/Dataset)와 최적화 엔진(Catalyst·Tungsten)으로 “왜 빠른가”를 이해하고, 셔플·파티셔닝·튜닝으로 “왜 느려지고 어떻게 고치는가”를 익힌 뒤, Structured StreamingPySpark 실무로 활용을 넓히고, 마지막으로 Iceberg/Delta 연동(레이크하우스 저장 포맷과의 결합)으로 마무리합니다. 각 단계를 정복할 때마다 상세 딥다이브 포스트를 작성하고 체크박스를 채우는 도장깨기 방식으로 진행합니다.

세 막으로 보는 Spark 학습 여정 — 돌아가게 하기 → 빠르고 안정적으로 → 활용 넓히기 세 막으로 보는 학습 여정 1 돌아가게 하기 무엇이 어떻게 실행되고, 왜 빠른가 1아키텍처 2추상화 (RDD·DF·DS) 3Catalyst·Tungsten 2 빠르고 안정적으로 셔플을 줄이고 다스리기 4셔플·튜닝 스큐 · 스필 · 조인 전략 실무 가치가 가장 큰 단계 3 활용 넓히기 배치를 넘어 스트림·레이크하우스로 5Structured Streaming 6PySpark 실무 7Iceberg·Delta 연동
학습 스파인을 세 막으로 — ① 돌아가게 하기(구조·추상화·옵티마이저) → ② 빠르고 안정적으로(셔플·튜닝) → ③ 활용 넓히기(스트리밍·PySpark·레이크하우스)

학습 흐름

7단계는 아래 순서대로 진행하는 것을 권장합니다. Spark가 무엇을 어떻게 실행하는지(아키텍처)를 먼저 그리고, 그 위에서 다루는 데이터 추상화와 그것을 빠르게 만드는 옵티마이저로 “왜 빠른가”를 이해합니다. 그다음 실무에서 반드시 부딪히는 셔플·성능 튜닝으로 “왜 느려지는가”를 다스리고, 스트리밍PySpark로 활용 범위를 넓힌 뒤, 레이크하우스 저장 포맷 연동으로 최신 데이터 스택에 Spark를 얹는 흐름입니다.

flowchart TD
    Start([학습 시작]) --> S1

    subgraph BASE["기반 · 무엇이 어떻게 실행되는가"]
        S1["1단계<br/>아키텍처<br/>Driver·Executor·실행 흐름"]
        S2["2단계<br/>핵심 추상화<br/>RDD·DataFrame·Dataset"]
        S3["3단계<br/>Catalyst·Tungsten<br/>쿼리 최적화·코드 생성"]
    end

    subgraph TUNE["성능 · 왜 느려지고 어떻게 고치는가"]
        S4["4단계<br/>셔플·파티셔닝·튜닝<br/>스큐·스필·조인 전략"]
    end

    subgraph APPLY["활용 · 범위를 넓히기"]
        S5["5단계<br/>Structured Streaming<br/>마이크로배치·워터마크·상태"]
        S6["6단계<br/>PySpark 실무<br/>API·UDF·pandas API on Spark"]
        S7["7단계 (심화)<br/>Iceberg·Delta 연동<br/>레이크하우스 저장 포맷"]
    end

    S1 --> S2 --> S3 --> S4 --> S5 --> S6 --> S7
    S7 --> Done([시리즈 완주])

학습 진행 현황

완료한 항목에는 상세 포스트 링크가 연결됩니다. 학습이 진행될 때마다 체크박스와 진행률을 갱신합니다.

  • 현재 완료한 항목: 0개
  • 전체 항목: 7개
  • 진행률: 0%

1단계: 아키텍처 — Driver/Executor·클러스터 매니저·실행 흐름

Spark 성능과 디버깅의 모든 것이 여기서 출발합니다. 하나의 Driver가 사용자 코드를 실행 계획(DAG)으로 세워 작업을 분배하고, 여러 Executor가 클러스터 각 노드에서 실제 task를 수행합니다. 그 사이에서 자원을 배분하는 클러스터 매니저(YARN·Kubernetes·Standalone)의 역할과, 하나의 액션이 Job → Stage → Task로 쪼개지는 실행 흐름을 익힙니다. 스테이지의 경계가 왜 셔플 지점인지까지 잡으면 이후 모든 단계가 이 그림 위에 얹힙니다.

  • Driver와 Executor: 실행 계획을 세우는 두뇌와 task를 수행하는 일꾼, 그리고 둘의 통신
  • 클러스터 매니저: YARN·Kubernetes·Standalone의 자원 배분과 배포 모델(client vs cluster)
  • 실행 흐름: 액션 → Job → Stage → Task 분해, 스테이지 경계와 셔플의 관계

2단계: RDD / DataFrame / Dataset — 핵심 추상화와 차이

Spark로 다루는 데이터의 세 가지 얼굴을 구분하는 단계입니다. 1세대 저수준 추상화인 RDD(계보 기반 내결함성을 주지만 최적화 여지가 적음), 스키마가 있어 옵티마이저가 개입할 수 있는 DataFrame, 그리고 타입 안전성을 더한 Dataset의 차이와 각각을 언제 쓰는지를 익힙니다. 아울러 변환은 계획만 쌓고 액션에서 한꺼번에 실행하는 lazy evaluation, 노드 안에서 끝나는 narrow와 셔플을 부르는 wide 트랜스포메이션의 구분을 여기서 확실히 잡습니다.

  • RDD: 분산 불변 컬렉션, 계보(lineage) 기반 내결함성, 저수준 제어의 쓰임새
  • DataFrame / Dataset: 스키마 기반 고수준 API, 타입 안전성, 무엇을 언제 선택할까
  • lazy evaluation과 트랜스포메이션: 변환 vs 액션, narrow vs wide 트랜스포메이션

3단계: Catalyst 옵티마이저 · Tungsten 실행 엔진 — 쿼리 최적화/코드 생성

DataFrame이 RDD보다 빠른 이유가 여기 있습니다. Catalyst 옵티마이저는 사용자 쿼리를 논리 계획 → 최적화된 논리 계획 → 물리 계획으로 변환하며 조건 푸시다운·컬럼 프루닝·조인 재정렬 같은 최적화를 적용합니다. Tungsten 실행 엔진은 그 물리 계획을 JVM 오버헤드를 줄인 메모리 관리와 whole-stage code generation으로 실행합니다. 여기에 런타임 통계로 계획을 다시 짜는 AQE(Adaptive Query Execution)까지 이해하면 “왜 이 쿼리가 이렇게 실행되는가”를 읽을 수 있게 됩니다.

  • Catalyst 옵티마이저: 논리 → 물리 계획 변환, 규칙 기반·비용 기반 최적화
  • Tungsten 실행 엔진: 메모리 관리, whole-stage code generation
  • Adaptive Query Execution(AQE): 런타임 통계 기반 계획 재조정

4단계: 셔플 · 파티셔닝 · 성능 튜닝 — 스큐·스필·조인 전략

Spark 실무에서 가장 자주, 가장 아프게 부딪히는 지점입니다. 노드 사이에서 키를 재배치하는 셔플은 늘 가장 비싼 연산이고, 성능 튜닝의 대부분은 셔플을 줄이거나 다스리는 일입니다. 파티셔닝 전략(파티션 수·repartition vs coalesce·파티션 프루닝), 한 키에 데이터가 쏠리는 데이터 스큐와 메모리를 넘겨 디스크로 흘리는 스필(spill), 그리고 broadcast·sort-merge·shuffle-hash 같은 조인 전략 선택을 다룹니다. Spark UI로 병목을 읽는 법까지 함께 익힙니다.

  • 셔플과 파티셔닝: 셔플의 비용, 파티션 수 조정, repartition/coalesce, 파티션 프루닝
  • 스큐와 스필: 데이터 스큐 완화(salting·AQE skew join), 메모리/디스크 스필 진단
  • 조인 전략: broadcast · sort-merge · shuffle-hash join의 선택 기준과 Spark UI 읽기

5단계: Spark Structured Streaming — 마이크로배치·워터마크·상태

Spark를 배치 너머 실시간으로 확장하는 단계입니다. Structured Streaming은 무한한 스트림을 계속 자라는 테이블로 보고, 배치와 거의 같은 DataFrame API로 다루게 해 줍니다. 흐름을 잘게 나눠 처리하는 마이크로배치 모델, 이벤트 시간 집계에서 언제 윈도를 닫을지 정하는 워터마크, 집계·조인·중복 제거를 위한 상태(state) 관리, 그리고 정확히 한 번 처리를 보장하는 체크포인트와 출력 모드를 익힙니다. (스트림 처리의 시간 개념은 오버뷰 처리 포스트의 이벤트 시간·워터마크·윈도잉 절이 좋은 사전 지식입니다.)

  • 마이크로배치 모델: 스트림을 계속 자라는 테이블로 보기, 배치와 통합된 API
  • 워터마크와 윈도잉: 이벤트 시간 집계, 지각 데이터 처리, 텀블링/슬라이딩/세션
  • 상태와 정확성: 상태 저장 연산, 체크포인트, 출력 모드와 exactly-once 보장

6단계: PySpark 실무 — API·UDF·pandas API on Spark

현실의 Spark 코드 대부분은 PySpark로 작성됩니다. Python API의 구조와 JVM과의 경계, 성능을 좌우하는 UDF의 종류(Python UDF vs Pandas UDF/Arrow 기반 벡터화 UDF)와 그 비용, 그리고 기존 pandas 코드를 분산 실행으로 옮기는 pandas API on Spark를 다룹니다. Python↔JVM 직렬화 오버헤드를 어떻게 피하는지, 언제 UDF 대신 내장 함수를 써야 하는지 같은 실무 감각을 함께 익힙니다.

  • PySpark API: Python 진입점과 JVM 경계, DataFrame/SQL 실무 패턴
  • UDF: Python UDF vs Pandas(벡터화) UDF, 직렬화 비용과 내장 함수 우선 원칙
  • pandas API on Spark: 기존 pandas 코드를 분산 실행으로 확장하기

7단계 (심화): Iceberg / Delta 연동 — 레이크하우스 저장 포맷과의 결합

마지막은 Spark를 2026년 레이크하우스 스택에 얹는 심화 단계입니다. 오버뷰 저장 포스트에서 소개한 오픈 테이블 포맷 — Apache Iceberg·Delta Lake — 을 Spark에서 읽고 쓰는 법을 다룹니다. 레이크 위에 ACID·시간여행(time travel)·스키마 진화를 얹는 테이블 포맷과 Spark를 결합하면, MERGE·업서트·증분 처리 같은 웨어하우스급 연산을 오브젝트 스토리지 위에서 수행할 수 있습니다. compaction·스냅샷 관리 같은 유지보수까지 짚습니다.

  • 테이블 포맷 기초: Iceberg·Delta의 메타데이터·스냅샷·ACID·시간여행
  • Spark에서 읽고 쓰기: MERGE/업서트, 스키마 진화, 파티션 진화
  • 유지보수: compaction, 스냅샷 만료, 증분 처리 패턴

핵심 포인트

  • 구조를 알아야 튜닝이 보인다: Spark를 돌아가게 만드는 것과 빠르게 만드는 것은 다른 문제입니다. Driver/Executor·Stage/Task·셔플이라는 실행 그림을 손에 쥐면, 성능 문제를 “느리다”가 아니라 “여기 셔플이 과하다”로 읽게 됩니다.
  • 추상화가 최적화를 부른다: RDD 대신 DataFrame/SQL을 쓰는 이유는 취향이 아니라 Catalyst·Tungsten이 개입할 수 있기 때문입니다. 고수준 API가 대개 더 빠릅니다.
  • 셔플이 늘 범인이다: 대규모 처리 성능 튜닝의 대부분은 “셔플을 줄이거나 다스리는 것”으로 귀결됩니다. 스큐·스필·조인 전략은 모두 셔플을 둘러싼 문제입니다.
  • 배치와 스트림은 하나의 엔진에서: Structured Streaming은 배치와 거의 같은 API로 스트림을 다룹니다. 배치에서 익힌 것이 그대로 실시간으로 이어집니다.
  • Spark는 레이크하우스의 처리 엔진이다: Iceberg·Delta 같은 테이블 포맷과 결합할 때, Spark는 단순 배치 도구를 넘어 오브젝트 스토리지 위의 웨어하우스급 처리 엔진이 됩니다.

추천 학습 순서

위 단계 번호 순서대로 진행하는 것을 권합니다.

  1. 기반(1~3단계) — 아키텍처로 “무엇이 어떻게 실행되는가”를 그리고, 추상화와 옵티마이저로 “왜 빠른가”를 이해합니다. 이 토대 없이 튜닝부터 손대면 증상만 쫓게 됩니다.
  2. 성능(4단계) — 셔플·파티셔닝·조인 전략으로 “왜 느려지고 어떻게 고치는가”를 다룹니다. 실무에서 가장 가치가 큰 단계입니다.
  3. 활용(5~7단계) — Structured Streaming으로 실시간을, PySpark로 실무 코드를, 그리고 Iceberg/Delta 연동으로 최신 레이크하우스 스택으로 Spark의 활용 범위를 넓힙니다.

각 단계는 앞 단계의 토대 위에 쌓이므로, 순서대로 정복하며 체크박스를 채워 나가길 권합니다.

결론

Spark는 “대용량을 나눠서 처리한다”는 단순한 발상 위에, 그것을 빠르고 안정적으로 만들기 위한 정교한 실행 엔진을 얹은 시스템입니다. 개별 API는 계속 진화하지만, Driver/Executor로 일을 나누고, DAG로 최적화하고, 셔플로 다시 모은다는 뼈대와 “고수준 추상화가 옵티마이저를 부른다”는 원리는 오래 갑니다. 이 7단계를 순서대로 정복하면, Spark 잡의 실행 계획과 Spark UI를 읽고 병목을 짚어내는 안목, 그리고 배치에서 스트리밍·레이크하우스까지 Spark를 확장하는 실무 감각을 갖추게 됩니다.

Spark-Essential 시리즈는 Data-Engineering-Essential 오버뷰가 예고한 심화 스핀오프의 첫 시리즈입니다. 오버뷰가 함께 약속한 수집의 Kafka, 변환의 dbt, 오케스트레이션의 Airflow 역시 각각 별도의 *-Essential 시리즈로 이어질 예정입니다.

다음 학습 (Next Learning)