Apache Spark 구조
Apache Spark는 분산 컴퓨팅 환경에서 대규모 데이터를 빠르게 처리할 수 있도록 설계된 클러스터 컴퓨팅 프레임워크임.
Spark의 구조(아키텍처)를 이해하려면 먼저 Spark가 어떻게 동작하는지, 어떤 컴포넌트로 구성되어 있는지, 그리고 내부에서 어떤 메커니즘으로 최적화가 이루어지는지를 살펴볼 필요가 있음.
핵심 컴포넌트 개요
Apache Spark에는 크게 다음과 같은 핵심 컴포넌트들이 존재함.
1. Driver (스파크 드라이버)
2. Cluster Manager (클러스터 매니저)
3. Executors (실행기)
4. SparkSession / SparkContext (애플리케이션 진입점)
5. RDD / Dataset / DataFrame (데이터 추상화)
6. Catalyst Optimizer (쿼리 최적화 엔진)
7. Scheduler (단계(DAG) 및 태스크 스케줄러)
각각이 어떤 역할을 하는지, 어떻게 상호작용하는지 파악하면 Spark의 구조를 이해하기 쉬워짐.
클라이언트 관점에서의 주요 요소
1. SparkSession / SparkContext
Spark를 사용하여 애플리케이션을 작성할 때 가장 먼저 생성하는 객체가 SparkSession임.
(Spark 2.x 이전에는 SparkContext와 SQLContext, HiveContext 등을 사용했으나, Spark 2.x부터는 SparkSession으로 통합되었습니다.)
SparkSession: SparkApplication(사용자 코드)과 Spark 클러스터(드라이버, 익스큐터, 클러스터 매니저) 사이에서 모든 것을 총괄하는 진입점 역할을 함.
내부적으로 SparkContext를 포함하며, 해당 애플리케이션의 유일무이한 컨텍스트로서 자원을 할당하고 작업(Job)을 제출함.
val spark = SparkSession.builder()
.appName("SparkApp")
.master("local[*]")
.getOrCreate()
2. Driver (스파크 드라이버)
사용자 코드(애플리케이션)를 직접 구동하고, Task 스케줄링(DAG 생성 및 작업 분배)을 총괄하는 프로세스임.
SparkContext(SparkSession) 내부에서 실행되며, 클러스터 매니저와 통신하고, 필요한 자원을 할당받음.
또한 Job을 Stage로 분할하고, Stage를 Task로 다시 쪼개어 Executors에게 전달함.
모든 RDD/Dataset/DataFrame의 실행 플랜(Execution Plan)을 관리하며, 최적화 로직(Catalyst Optimizer)에 의해 물리적 실행 계획을 세움.
3. Executors (실행기)
Driver가 보낸 Task를 실제로 실행하는 워크 노드(Worker Node) 상의 프로세스임.
Executor는 메모리와 CPU를 할당받아, RDD 파티션 데이터 혹은 Dataset의 파티션을 처리함.
Spark는 Executor들이 각종 연산을 수행한 결과를 메모리에 캐싱할 수 있게 하여, 반복 연산 시 높은 성능을 보장함.
Executor는 보통 멀티 스레드로 구성되어 여러 Task를 동시에 처리할 수 있고, Executor 수와 CPU 코어 수에 따라 전체적인 처리 성능이 좌우됨.
4. Cluster Manager (클러스터 매니저)
Spark 애플리케이션에 필요한 자원을 할당하고, Executor 프로세스를 시작/중지하는 등 클러스터 리소스를 관리함.
Spark는 여러 종류의 Cluster Manager와 연동 가능함.
Standalone Cluster Manager: Spark 자체 내장 클러스터 매니저
Apache YARN: Hadoop 생태계에 자주 쓰이는 자원 관리 프레임워크
Mesos
Kubernetes: 최근에는 Spark on K8s 환경도 많이 활용
Spark Application은 Cluster Manager에 Resource Request를 요청하고, Cluster Manager가 Executor 프로세스를 적절히 배포 및 실행하는 구조임.
내부 실행 메커니즘
Spark의 구조적 특징 중 하나는 RDD(Resilient Distributed Dataset)를 이용한 분산 데이터 처리를 기반으로 한다는 점임.
RDD를 비롯해 Dataset, DataFrame 등의 API는 내부에서 비슷한 실행 플랜을 거침.
1. RDD (Resilient Distributed Dataset)
Spark의 가장 기본이 되는 분산 데이터 추상화임.
데이터에 대한 불변(Immutable), 계산 지연(Lazy Evaluation), 분산 컬렉션의 특성을 가짐.
Transformations(맵, 필터, 조인, 그룹바이 등)과 Actions(collect, count, save 등)을 통해 RDD를 다룸.
계산 계보(Lineage)를 저장하여 장애 발생 시 특정 파티션의 RDD만 재연산해 복구할 수 있음.
2. Dataset / DataFrame
Spark SQL 엔진 상에서 RDD 위에 추상화를 얹은 구조로, 스키마(열 이름, 데이터 타입)를 인식하고 열 기반 최적화 기능을 제공함.
Catalyst Optimizer를 통해 SQL 쿼리나 DataFrame API를 실행할 때 논리적 실행 계획을 물리적 실행 계획으로 최적화함.
Dataset은 타입 정보를 포함하는 구조화된 API, DataFrame은 Row 단위의 구조화된 데이터 핸들링에 중점을 둔 API임.
(Scala/Java에서는 Dataset<Row>가 DataFrame과 거의 동일).
3. Catalyst Optimizer
Catalyst Optimizer는 Spark SQL의 쿼리 최적화 엔진임.
정적/동적 최적화 기법을 결합하여 다음과 같은 단계를 거쳐 쿼리를 최적화함
3-1. 논리적 계획(Logical Plan) 생성
사용자가 작성한 SQL 또는 DataFrame 연산을 파싱, 분석하여 논리적 트리 형태로 표현함.
3-2. 논리적 최적화(Logical Optimization)
필터 푸시다운, 중복 제거, 불필요한 컬럼 제거(Project Pruning), 연산 재배열 등 다양한 규칙 기반 최적화를 수행함.
3-3. 물리적 계획(Physical Plan) 생성
최적화된 논리적 계획을 기반으로 실제 실행에 가까운 물리적 연산 트리로 변환함.
Exchange(Shuffle), Sort, Join 알고리즘(Broadcast Hash Join, Sort Merge Join 등)의 선택 등 구체적인 실행 전략을 결정함.
3-4. 물리적 최적화(Physical Optimization)
코스트 기반의 실행 전략(CBO, Cost-Based Optimization)을 일부 적용하여 최적의 물리적 연산자를 선택하고, 일부 연산은 코드 생성을 통해 추가 최적화(Codegen)도 수행함.
이 과정을 거쳐 최종 태스크로 분해되어 Executors에서 병렬 처리됨.
4. DAG (Directed Acyclic Graph) 기반 스케줄링
Spark가 Job을 실행할 때는 DAG(방향성 비순환 그래프) 형식으로 실행 단계를 모델링함.
4-1. 사용자가 Transformations를 체인처럼 이어 붙여 RDD나 Dataset을 정의한 뒤, Action 연산을 호출하면 Job이 생성됨.
4-2. Spark Driver는 RDD 간의 의존관계를 분석하여 Stage를 나누고(일반적으로 Shuffle 경계를 기준으로 분할), 각 Stage를 여러 개의 Task로 다시 분할함.
4-3. Stage가 DAG 상에서 의존하는 Stage들이 모두 완료된 시점에 해당 Stage의 Task들을 실행함.
4-4. Stage 내 Task들은 Executor에 분산 배치되어 병렬로 처리됨.
4-5. Job의 모든 Stage가 성공적으로 완료되면 최종 Action 결과가 반환됨.
이를 통해 Spark는 파이프라이닝, 태스크 병렬화, 지연 평가 등을 결합하여 높은 성능을 발휘함.
클러스터 동작 단계 정리
Spark 애플리케이션이 실행되는 전형적인 단계를 정리해보면 다음과 같음.
1. 사용자 코드 작성 및 Submit
사용자는 SparkSession을 생성하고, RDD/DataFrame/Dataset 연산을 수행하는 코드를 작성함.
spark-submit 명령(또는 내부 API)을 통해 클러스터에 애플리케이션을 제출함.
2. Driver 프로세스 기동
클러스터 매니저로부터 자원을 할당받아 Driver 프로세스가 실행됨.
Driver 안에서 SparkSession이 초기화되고, SparkContext가 동작하며, DAG Scheduler 등이 구동됨.
3. Executors 할당 및 초기화
Driver는 클러스터 매니저에게 요청해 필요한 Executor 수, 메모리, CPU 코어 등을 할당받음.
Worker 노드마다 Executor 프로세스가 기동되고, SparkContext와 통신을 맺음.
4. Job 생성 및 DAG 스케줄링
사용자가 작성한 Transformations는 지연 평가(실제로는 연산 실행이 안 일어남)로 표현만 되어있고, Action을 만나는 순간 Job이 생성됨.
Catalyst Optimizer와 DAG Scheduler가 논리적/물리적 실행 계획을 생성하고 Stage/Task로 분할함.
5. Task 배포 및 실행
Driver가 각 Executor에게 Task를 배포함.
각 Task는 자신의 파티션 데이터를 처리하여 결과를 내거나, 중간 Shuffle 파일을 생성하여 다음 Stage에 전달함.
6. 결과 취합 및 반환
모든 Stage가 성공적으로 완료되면 Action 결과(예: collect(), count() 등)는 Driver에 취합되어 사용자에게 반환됨.
Job 실행이 종료되면 Executor와 Driver 프로세스는 자원 반납 후 종료할 수 있음.
성능 최적화와 장점
1. 인메모리(In-memory) 컴퓨팅
RDD, Dataset 연산에서 중간 결과를 메모리에 보관하여 반복 연산을 빠르게 수행함.
2. Lazy Evaluation(지연 평가)
Transformations 체인을 DAG로 구성하고, 실제 연산은 Action이 실행될 때 최적화 과정을 거쳐 한 번에 실행함.
3. 라인리지(Lineage) 기반 내결함성
각 RDD에 대한 의존 관계를 추적(Lineage Graph)하기 때문에 특정 파티션이 유실되더라도 재연산으로 쉽게 복구함.
4. Catalyst Optimizer
고급 쿼리 최적화 방식을 도입해 SQL과 DataFrame, Dataset API를 높은 수준으로 튜닝함.
5. 풍부한 API 지원
RDD, DataFrame/Dataset, SQL, MLlib(머신러닝), GraphX(그래프 처리) 등 다양한 API를 통해 확장성과 범용성을 제공함.
6. 다양한 클러스터 매니저 및 환경 지원
Standalone, YARN, Mesos, Kubernetes 등 다양한 환경에서 동작함.
정리
Apache Spark의 구조는 크게 Driver-Executor 모델을 기반으로, DAG 스케줄링과 Catalyst Optimizer에 의해 고도의 병렬 처리를 수행하도록 설계되어 있음.
Driver는 전체 작업 플로우를 관리하고, Executor는 분산된 데이터 파티션에 대한 실제 연산을 담당하며, Catalyst Optimizer는 데이터 연산(특히 SQL 계열)을 최적화해줌.
이러한 구조적 특징은 대규모 데이터셋을 빠르게 처리할 수 있는 Spark의 강력한 성능의 원천임.
Driver: 중앙에서 스케줄링과 최적화 담당
Executors: 분산된 데이터 연산 담당
Cluster Manager: 자원 할당 및 Executor 관리
Catalyst Optimizer: SQL/DataFrame 연산 최적화 엔진
RDD / Dataset / DataFrame: 추상화 계층을 제공해 사용자에게 편리한 API 제공
DAG 스케줄링: 효율적이고 병렬화된 분산 처리의 핵심
이와 같은 구조적 설계 덕분에 Spark는 높은 처리 성능뿐만 아니라 확장성, 유연성, 내결함성을 고루 갖춘 분산 컴퓨팅 플랫폼으로 자리매김하고 있음.
'Data Engineering > Spark' 카테고리의 다른 글
[Spark] Disk Spill (0) | 2025.03.28 |
---|---|
[Spark] SparkSQL의 Window함수 종류 (1) | 2025.03.22 |
[Spark] Apache Iceberg (2) | 2025.03.14 |
[Spark] Apache ORC 파일 구조 (0) | 2025.03.09 |
[Spark] Apache Parquet 파일 구조 (0) | 2025.03.09 |
Apache Spark 구조
Apache Spark는 분산 컴퓨팅 환경에서 대규모 데이터를 빠르게 처리할 수 있도록 설계된 클러스터 컴퓨팅 프레임워크임.
Spark의 구조(아키텍처)를 이해하려면 먼저 Spark가 어떻게 동작하는지, 어떤 컴포넌트로 구성되어 있는지, 그리고 내부에서 어떤 메커니즘으로 최적화가 이루어지는지를 살펴볼 필요가 있음.
핵심 컴포넌트 개요
Apache Spark에는 크게 다음과 같은 핵심 컴포넌트들이 존재함.
1. Driver (스파크 드라이버)
2. Cluster Manager (클러스터 매니저)
3. Executors (실행기)
4. SparkSession / SparkContext (애플리케이션 진입점)
5. RDD / Dataset / DataFrame (데이터 추상화)
6. Catalyst Optimizer (쿼리 최적화 엔진)
7. Scheduler (단계(DAG) 및 태스크 스케줄러)
각각이 어떤 역할을 하는지, 어떻게 상호작용하는지 파악하면 Spark의 구조를 이해하기 쉬워짐.
클라이언트 관점에서의 주요 요소
1. SparkSession / SparkContext
Spark를 사용하여 애플리케이션을 작성할 때 가장 먼저 생성하는 객체가 SparkSession임.
(Spark 2.x 이전에는 SparkContext와 SQLContext, HiveContext 등을 사용했으나, Spark 2.x부터는 SparkSession으로 통합되었습니다.)
SparkSession: SparkApplication(사용자 코드)과 Spark 클러스터(드라이버, 익스큐터, 클러스터 매니저) 사이에서 모든 것을 총괄하는 진입점 역할을 함.
내부적으로 SparkContext를 포함하며, 해당 애플리케이션의 유일무이한 컨텍스트로서 자원을 할당하고 작업(Job)을 제출함.
val spark = SparkSession.builder()
.appName("SparkApp")
.master("local[*]")
.getOrCreate()
2. Driver (스파크 드라이버)
사용자 코드(애플리케이션)를 직접 구동하고, Task 스케줄링(DAG 생성 및 작업 분배)을 총괄하는 프로세스임.
SparkContext(SparkSession) 내부에서 실행되며, 클러스터 매니저와 통신하고, 필요한 자원을 할당받음.
또한 Job을 Stage로 분할하고, Stage를 Task로 다시 쪼개어 Executors에게 전달함.
모든 RDD/Dataset/DataFrame의 실행 플랜(Execution Plan)을 관리하며, 최적화 로직(Catalyst Optimizer)에 의해 물리적 실행 계획을 세움.
3. Executors (실행기)
Driver가 보낸 Task를 실제로 실행하는 워크 노드(Worker Node) 상의 프로세스임.
Executor는 메모리와 CPU를 할당받아, RDD 파티션 데이터 혹은 Dataset의 파티션을 처리함.
Spark는 Executor들이 각종 연산을 수행한 결과를 메모리에 캐싱할 수 있게 하여, 반복 연산 시 높은 성능을 보장함.
Executor는 보통 멀티 스레드로 구성되어 여러 Task를 동시에 처리할 수 있고, Executor 수와 CPU 코어 수에 따라 전체적인 처리 성능이 좌우됨.
4. Cluster Manager (클러스터 매니저)
Spark 애플리케이션에 필요한 자원을 할당하고, Executor 프로세스를 시작/중지하는 등 클러스터 리소스를 관리함.
Spark는 여러 종류의 Cluster Manager와 연동 가능함.
Standalone Cluster Manager: Spark 자체 내장 클러스터 매니저
Apache YARN: Hadoop 생태계에 자주 쓰이는 자원 관리 프레임워크
Mesos
Kubernetes: 최근에는 Spark on K8s 환경도 많이 활용
Spark Application은 Cluster Manager에 Resource Request를 요청하고, Cluster Manager가 Executor 프로세스를 적절히 배포 및 실행하는 구조임.
내부 실행 메커니즘
Spark의 구조적 특징 중 하나는 RDD(Resilient Distributed Dataset)를 이용한 분산 데이터 처리를 기반으로 한다는 점임.
RDD를 비롯해 Dataset, DataFrame 등의 API는 내부에서 비슷한 실행 플랜을 거침.
1. RDD (Resilient Distributed Dataset)
Spark의 가장 기본이 되는 분산 데이터 추상화임.
데이터에 대한 불변(Immutable), 계산 지연(Lazy Evaluation), 분산 컬렉션의 특성을 가짐.
Transformations(맵, 필터, 조인, 그룹바이 등)과 Actions(collect, count, save 등)을 통해 RDD를 다룸.
계산 계보(Lineage)를 저장하여 장애 발생 시 특정 파티션의 RDD만 재연산해 복구할 수 있음.
2. Dataset / DataFrame
Spark SQL 엔진 상에서 RDD 위에 추상화를 얹은 구조로, 스키마(열 이름, 데이터 타입)를 인식하고 열 기반 최적화 기능을 제공함.
Catalyst Optimizer를 통해 SQL 쿼리나 DataFrame API를 실행할 때 논리적 실행 계획을 물리적 실행 계획으로 최적화함.
Dataset은 타입 정보를 포함하는 구조화된 API, DataFrame은 Row 단위의 구조화된 데이터 핸들링에 중점을 둔 API임.
(Scala/Java에서는 Dataset<Row>가 DataFrame과 거의 동일).
3. Catalyst Optimizer
Catalyst Optimizer는 Spark SQL의 쿼리 최적화 엔진임.
정적/동적 최적화 기법을 결합하여 다음과 같은 단계를 거쳐 쿼리를 최적화함
3-1. 논리적 계획(Logical Plan) 생성
사용자가 작성한 SQL 또는 DataFrame 연산을 파싱, 분석하여 논리적 트리 형태로 표현함.
3-2. 논리적 최적화(Logical Optimization)
필터 푸시다운, 중복 제거, 불필요한 컬럼 제거(Project Pruning), 연산 재배열 등 다양한 규칙 기반 최적화를 수행함.
3-3. 물리적 계획(Physical Plan) 생성
최적화된 논리적 계획을 기반으로 실제 실행에 가까운 물리적 연산 트리로 변환함.
Exchange(Shuffle), Sort, Join 알고리즘(Broadcast Hash Join, Sort Merge Join 등)의 선택 등 구체적인 실행 전략을 결정함.
3-4. 물리적 최적화(Physical Optimization)
코스트 기반의 실행 전략(CBO, Cost-Based Optimization)을 일부 적용하여 최적의 물리적 연산자를 선택하고, 일부 연산은 코드 생성을 통해 추가 최적화(Codegen)도 수행함.
이 과정을 거쳐 최종 태스크로 분해되어 Executors에서 병렬 처리됨.
4. DAG (Directed Acyclic Graph) 기반 스케줄링
Spark가 Job을 실행할 때는 DAG(방향성 비순환 그래프) 형식으로 실행 단계를 모델링함.
4-1. 사용자가 Transformations를 체인처럼 이어 붙여 RDD나 Dataset을 정의한 뒤, Action 연산을 호출하면 Job이 생성됨.
4-2. Spark Driver는 RDD 간의 의존관계를 분석하여 Stage를 나누고(일반적으로 Shuffle 경계를 기준으로 분할), 각 Stage를 여러 개의 Task로 다시 분할함.
4-3. Stage가 DAG 상에서 의존하는 Stage들이 모두 완료된 시점에 해당 Stage의 Task들을 실행함.
4-4. Stage 내 Task들은 Executor에 분산 배치되어 병렬로 처리됨.
4-5. Job의 모든 Stage가 성공적으로 완료되면 최종 Action 결과가 반환됨.
이를 통해 Spark는 파이프라이닝, 태스크 병렬화, 지연 평가 등을 결합하여 높은 성능을 발휘함.
클러스터 동작 단계 정리
Spark 애플리케이션이 실행되는 전형적인 단계를 정리해보면 다음과 같음.
1. 사용자 코드 작성 및 Submit
사용자는 SparkSession을 생성하고, RDD/DataFrame/Dataset 연산을 수행하는 코드를 작성함.
spark-submit 명령(또는 내부 API)을 통해 클러스터에 애플리케이션을 제출함.
2. Driver 프로세스 기동
클러스터 매니저로부터 자원을 할당받아 Driver 프로세스가 실행됨.
Driver 안에서 SparkSession이 초기화되고, SparkContext가 동작하며, DAG Scheduler 등이 구동됨.
3. Executors 할당 및 초기화
Driver는 클러스터 매니저에게 요청해 필요한 Executor 수, 메모리, CPU 코어 등을 할당받음.
Worker 노드마다 Executor 프로세스가 기동되고, SparkContext와 통신을 맺음.
4. Job 생성 및 DAG 스케줄링
사용자가 작성한 Transformations는 지연 평가(실제로는 연산 실행이 안 일어남)로 표현만 되어있고, Action을 만나는 순간 Job이 생성됨.
Catalyst Optimizer와 DAG Scheduler가 논리적/물리적 실행 계획을 생성하고 Stage/Task로 분할함.
5. Task 배포 및 실행
Driver가 각 Executor에게 Task를 배포함.
각 Task는 자신의 파티션 데이터를 처리하여 결과를 내거나, 중간 Shuffle 파일을 생성하여 다음 Stage에 전달함.
6. 결과 취합 및 반환
모든 Stage가 성공적으로 완료되면 Action 결과(예: collect(), count() 등)는 Driver에 취합되어 사용자에게 반환됨.
Job 실행이 종료되면 Executor와 Driver 프로세스는 자원 반납 후 종료할 수 있음.
성능 최적화와 장점
1. 인메모리(In-memory) 컴퓨팅
RDD, Dataset 연산에서 중간 결과를 메모리에 보관하여 반복 연산을 빠르게 수행함.
2. Lazy Evaluation(지연 평가)
Transformations 체인을 DAG로 구성하고, 실제 연산은 Action이 실행될 때 최적화 과정을 거쳐 한 번에 실행함.
3. 라인리지(Lineage) 기반 내결함성
각 RDD에 대한 의존 관계를 추적(Lineage Graph)하기 때문에 특정 파티션이 유실되더라도 재연산으로 쉽게 복구함.
4. Catalyst Optimizer
고급 쿼리 최적화 방식을 도입해 SQL과 DataFrame, Dataset API를 높은 수준으로 튜닝함.
5. 풍부한 API 지원
RDD, DataFrame/Dataset, SQL, MLlib(머신러닝), GraphX(그래프 처리) 등 다양한 API를 통해 확장성과 범용성을 제공함.
6. 다양한 클러스터 매니저 및 환경 지원
Standalone, YARN, Mesos, Kubernetes 등 다양한 환경에서 동작함.
정리
Apache Spark의 구조는 크게 Driver-Executor 모델을 기반으로, DAG 스케줄링과 Catalyst Optimizer에 의해 고도의 병렬 처리를 수행하도록 설계되어 있음.
Driver는 전체 작업 플로우를 관리하고, Executor는 분산된 데이터 파티션에 대한 실제 연산을 담당하며, Catalyst Optimizer는 데이터 연산(특히 SQL 계열)을 최적화해줌.
이러한 구조적 특징은 대규모 데이터셋을 빠르게 처리할 수 있는 Spark의 강력한 성능의 원천임.
Driver: 중앙에서 스케줄링과 최적화 담당
Executors: 분산된 데이터 연산 담당
Cluster Manager: 자원 할당 및 Executor 관리
Catalyst Optimizer: SQL/DataFrame 연산 최적화 엔진
RDD / Dataset / DataFrame: 추상화 계층을 제공해 사용자에게 편리한 API 제공
DAG 스케줄링: 효율적이고 병렬화된 분산 처리의 핵심
이와 같은 구조적 설계 덕분에 Spark는 높은 처리 성능뿐만 아니라 확장성, 유연성, 내결함성을 고루 갖춘 분산 컴퓨팅 플랫폼으로 자리매김하고 있음.
'Data Engineering > Spark' 카테고리의 다른 글
[Spark] Disk Spill (0) | 2025.03.28 |
---|---|
[Spark] SparkSQL의 Window함수 종류 (1) | 2025.03.22 |
[Spark] Apache Iceberg (2) | 2025.03.14 |
[Spark] Apache ORC 파일 구조 (0) | 2025.03.09 |
[Spark] Apache Parquet 파일 구조 (0) | 2025.03.09 |