스파크 코어
1. 개요
1. 개요
Apache Spark의 핵심 구성 요소인 스파크 코어는 분산 데이터 처리의 기반을 제공하는 기본 엔진이다. 이는 Apache Software Foundation이 개발 및 배포한 오픈 소스 분산 컴퓨팅 프레임워크의 중심부에 위치하며, 2014년 5월 30일에 첫 번째 안정 버전이 공식 출시되었다. 스파크 코어는 대규모 데이터 처리를 위한 작업 스케줄링, 메모리 관리, 장애 복구, 그리고 저장 시스템과의 상호작용과 같은 기본적인 기능들을 담당한다.
스파크 코어의 가장 중요한 추상화는 RDD이다. RDD는 변경 불가능한 객체들의 컬렉션으로, 클러스터의 여러 노드에 걸쳐 분할되어 저장된다. 이 분산 데이터셋은 내결함성을 보장하며, 사용자는 병렬 연산을 적용할 수 있다. 스파크 코어는 이러한 RDD를 생성하고 조작하기 위한 다양한 변환 연산과 액션 연산을 제공하는 API를 포함하고 있다.
이 프레임워크는 인메모리 컴퓨팅을 적극 활용하여 Hadoop MapReduce와 같은 기존의 디스크 기반 처리 시스템에 비해 상당한 성능 향상을 이끌어낸다. 또한 스파크 코어는 배치 처리, 스트림 처리, 머신러닝 라이브러리, 그래프 처리를 위한 고수준 모듈들의 공통 기반 역할을 한다. 크로스 플랫폼으로 동작하며, Apache License 2.0 하에 자유롭게 사용할 수 있다.
2. 아키텍처
2. 아키텍처
2.1. 클러스터 매니저
2.1. 클러스터 매니저
스파크 코어는 클러스터 자원을 관리하고 애플리케이션 실행을 조율하는 클러스터 매니저 위에서 동작한다. 클러스터 매니저는 스파크 애플리케이션에 필요한 CPU와 메모리 자원을 할당하고, 익스큐터 프로세스를 여러 노드에 분산하여 실행하는 역할을 담당한다. 이를 통해 스파크는 단일 머신이 아닌 수백, 수천 대의 컴퓨터로 구성된 클러스터에서 대규모 데이터 처리를 수행할 수 있다.
스파크는 다양한 클러스터 매니저와 호환되도록 설계되어 있어, 사용자는 인프라 환경에 맞게 선택할 수 있다. 가장 기본적으로는 스파크 자체에 포함된 독립 실행형 스파크 스탠드얼론 클러스터 매니저를 사용할 수 있다. 또한 널리 사용되는 Apache Hadoop의 YARN이나 Apache Mesos와 같은 범용 클러스터 관리자 위에서도 실행된다. 최근에는 Kubernetes와 같은 컨테이너 오케스트레이션 플랫폼을 클러스터 매니저로 사용하는 것도 공식적으로 지원한다.
클러스터 매니저는 드라이버 프로그램과 협력하여 작업을 수행한다. 드라이버 프로그램이 애플리케이션 로직을 제출하면, 클러스터 매니저는 이를 수락하고 클러스터 내의 워커 노드에 자원을 할당하여 익스큐터를 실행한다. 이후 드라이버는 직접 익스큐터와 통신하여 작업을 분배하고 결과를 수집한다. 이러한 분리된 아키텍처는 스파크가 다양한 클러스터 환경에 유연하게 적응할 수 있게 해주는 핵심 요소이다.
2.2. 드라이버 프로그램
2.2. 드라이버 프로그램
드라이버 프로그램은 스파크 코어 애플리케이션의 핵심 제어 지점이다. 이 프로그램은 사용자가 작성한 메인 함수를 실행하며, 스파크 컨텍스트를 생성하고 전체 애플리케이션의 라이프사이클을 관리하는 역할을 한다. 드라이버 프로그램은 클러스터 매니저와 통신하여 애플리케이션 실행에 필요한 자원을 요청하고, 작업을 정의하며, 이를 익스큐터들에게 분배한다.
드라이버 프로그램의 주요 임무는 사용자의 애플리케이션 코드를 분석하여 RDD의 변환과 액션으로 구성된 논리적 실행 계획을 수립하는 것이다. 이후 이 계획은 물리적 실행 계획으로 변환되어 클러스터의 여러 노드에서 실행될 태스크들로 분해된다. 드라이버는 이러한 태스크들의 스케줄링과 모니터링을 담당하며, 최종 결과를 수집하거나 외부 저장소에 저장하는 작업도 수행한다.
드라이버 프로그램은 일반적으로 클러스터의 마스터 노드에서 실행되거나, 클라이언트 모드로 사용자의 로컬 머신에서 실행될 수 있다. 이는 스파크 코어 애플리케이션의 진입점이자 조정자로서, 분산 컴퓨팅 작업의 오케스트레이션을 총괄한다. 따라서 드라이버 프로그램의 가용성과 성능은 전체 애플리케이션의 안정성에 직접적인 영향을 미친다.
2.3. 익스큐터
2.3. 익스큐터
익스큐터는 스파크 코어 애플리케이션에서 실제 연산 작업을 수행하는 프로세스이다. 드라이버 프로그램이 생성한 태스크를 실행하는 주체로, 클러스터 매니저에 의해 애플리케이션별로 할당된 워커 노드 위에서 동작한다. 각 익스큐터는 독립적인 자바 가상 머신 프로세스로 실행되며, 할당받은 CPU 코어와 메모리 자원을 사용하여 태스크를 병렬로 처리한다.
익스큐터의 주요 역할은 RDD에 정의된 변환과 액션 연산을 실행하는 것이다. 이는 데이터를 읽고, 필터링하거나 맵 연산을 적용하며, 결과를 계산하거나 저장소에 쓰는 작업을 포함한다. 또한, 캐싱된 RDD의 데이터 파티션을 메모리나 디스크에 저장하여 재사용성을 높이는 책임도 가진다. 성능 최적화를 위해 브로드캐스트 변수를 로컬에 캐시하거나, 어큐뮬레이터 변수의 값을 업데이트하는 작업도 수행한다.
애플리케이션이 시작되면 드라이버 프로그램은 클러스터 매니저를 통해 필요한 수의 익스큐터 프로세스를 각 워커 노드에 생성한다. 이 익스큐터들은 애플리케이션의 수명 주기 동안 지속적으로 실행되며, 여러 개의 태스크를 순차적으로 또는 병렬로 처리한다. 익스큐터는 태스크 실행 상태와 결과를 지속적으로 드라이버 프로그램에 보고하여, 드라이버가 전체 작업 흐름을 조정하고 모니터링할 수 있도록 한다.
익스큐터 프로세스는 태스크 실행 중에 장애가 발생하더라도 내결함성 메커니즘의 일부로 동작한다. 만약 특정 익스큐터가 실패하면, 클러스터 매니저는 다른 워커 노드에서 새로운 익스큐터를 시작할 수 있으며, 드라이버 프로그램은 실패한 태스크를 다른 익스큐터에게 다시 스케줄링하여 작업을 완료한다. 이 구조는 분산 컴퓨팅 환경에서의 안정적인 작업 처리를 보장한다.
2.4. RDD (Resilient Distributed Dataset)
2.4. RDD (Resilient Distributed Dataset)
RDD는 스파크 코어의 기본 데이터 추상화 모델이다. 이는 분산된 컴퓨팅 클러스터의 여러 노드에 걸쳐 저장된 변경 불가능한 객체의 컬렉션을 나타낸다. RDD는 메모리 내에서 데이터를 처리할 수 있도록 설계되어 디스크 기반 시스템에 비해 처리 속도를 크게 향상시킨다. 각 RDD는 자동으로 복구 가능한 방식으로 분할되며, 이를 통해 시스템은 내결함성을 확보한다.
RDD는 크게 두 가지 유형의 연산을 지원한다. 첫 번째는 변환 연산으로, 기존 RDD로부터 새로운 RDD를 생성하는 지연 실행 연산이다. 대표적인 예로 map, filter, join 등이 있다. 두 번째는 액션 연산으로, RDD에 대한 계산을 수행하고 그 결과를 드라이버 프로그램에 반환하거나 외부 저장소에 쓰는 연산이다. count, collect, saveAsTextFile 등이 여기에 해당한다. 이러한 지연 실행 모델은 스파크가 전체 작업 흐름을 최적화할 수 있게 한다.
RDD의 내결함성은 데이터의 계보 또는 라인지 정보를 추적함으로써 구현된다. RDD는 자신이 어떤 다른 RDD들로부터, 어떤 변환 연산을 통해 생성되었는지에 대한 정보를 유지한다. 만약 어떤 파티션 데이터가 유실되면, 스파크는 이 계보 정보를 사용해 원본 데이터로부터 해당 파티션만을 다시 계산하여 복구한다. 이 방식은 데이터를 복제하는 전통적인 방법보다 효율적인 장점을 가진다.
RDD는 다양한 데이터 소스로부터 생성될 수 있다. HDFS나 로컬 파일 시스템의 파일, 기존의 스칼라 컬렉션, 또는 아파치 하이브, 아파치 HBase와 같은 다른 분산 데이터베이스가 그 예이다. 또한 키-값 쌍 형태의 RDD는 어그리게이션이나 데이터 조인 연산에 특화된 추가적인 연산을 제공하여, 복잡한 데이터 처리 작업을 효율적으로 수행할 수 있도록 돕는다.
3. 주요 기능
3. 주요 기능
3.1. 메모리 내 연산
3.1. 메모리 내 연산
스파크 코어의 핵심 특징 중 하나는 메모리 내 연산을 통해 데이터 처리 성능을 극대화한다는 점이다. 기존의 하둡 맵리듀스와 같은 디스크 기반 처리 모델은 중간 결과를 반복적으로 하드 디스크에 읽고 쓰는 과정에서 발생하는 입출력 오버헤드로 인해 성능에 제약이 있었다. 반면, 스파크는 RDD라는 추상화된 데이터 구조를 이용해 작업 중간 데이터를 가능한 한 주 메모리에 보관하고 재사용함으로써 이러한 오버헤드를 획기적으로 줄인다.
이러한 설계 덕분에 반복적인 알고리즘이나 데이터 마이닝 작업, 머신러닝 모델 학습과 같은 반복 작업에서 매우 빠른 성능을 보여준다. 예를 들어, 동일한 데이터셋에 대해 여러 번의 쿼리를 수행하거나, 그래프 알고리즘처럼 단계별로 데이터를 업데이트하는 작업에서 이점이 크다. 메모리 용량이 충분하다면, 맵리듀스에 비해 수십 배에서 수백 배 빠른 처리 속도를 달성할 수 있다.
물론 모든 데이터를 메모리에 올릴 수 없는 경우도 있다. 스파크는 이를 위해 RDD의 내결함성을 유지하면서 메모리가 부족할 때는 일부 데이터를 디스크로 내보내는 지능적인 메모리 관리 전략을 사용한다. 이는 사용자에게 투명하게 이루어지며, 개발자는 복잡한 메모리 관리를 신경 쓰지 않고도 고수준 API를 통해 효율적인 애플리케이션을 작성할 수 있다. 결과적으로 스파크 코어의 메모리 내 연산 모델은 대규모 데이터 처리의 새로운 패러다임을 제시하며, 배치 처리부터 인터랙티브 쿼리, 실시간 분석에 이르기까지 다양한 워크로드에 적합한 고성능 엔진의 기반이 된다.
3.2. 내결함성
3.2. 내결함성
스파크 코어의 내결함성은 시스템의 핵심 설계 원칙 중 하나로, 클러스터 환경에서 노드나 태스크가 실패하더라도 전체 작업을 성공적으로 완료할 수 있도록 보장한다. 이는 주로 RDD의 불변성과 계보 정보를 활용한 재계산 메커니즘을 통해 구현된다. RDD는 데이터의 변환 과정을 기록하는 계보를 유지하며, 만약 특정 파티션의 데이터가 손실되면 이 계보 정보를 따라 원본 데이터로부터 필요한 부분만을 다시 계산하여 복구한다. 이 방식은 데이터를 디스크에 지속적으로 저장하는 오버헤드를 줄이면서도 장애 복구를 가능하게 한다.
내결함성은 클러스터 매니저와 익스큐터 간의 협력으로 관리된다. 드라이버 프로그램은 작업을 태스크 단위로 분할하여 익스큐터에 할당하고, 각 익스큐터의 실행 상태를 모니터링한다. 만약 특정 익스큐터가 응답하지 않거나 태스크 실행에 실패하면, 클러스터 매니저는 다른 가용한 익스큐터에 해당 태스크를 재할당한다. 이 과정에서 RDD의 계보 정보는 재계산의 범위를 최소화하는 데 사용되어, 전체 작업의 지연을 최소화한다.
3.3. 지연 실행
3.3. 지연 실행
지연 실행은 Apache Spark의 핵심적인 실행 모델이다. 이는 사용자가 작성한 변환 연산이 즉시 실행되는 것이 아니라, 실제로 결과가 필요할 때까지 실행을 미루는 방식을 의미한다. 드라이버 프로그램은 사용자의 코드를 분석하여 실행 계획인 DAG를 생성하지만, 이 계획은 즉시 클러스터에 전달되어 실행되지 않는다. 대신, 액션 연산이 호출될 때까지 모든 변환 명령은 단순히 논리적 실행 계획으로만 축적된다.
이러한 접근 방식은 몇 가지 중요한 이점을 제공한다. 첫째, Spark는 전체 작업 흐름을 한눈에 파악할 수 있어 최적화를 수행할 수 있다. 예를 들어, 불필요한 중간 데이터 생성을 피하거나 여러 연산을 하나의 스테이지로 병합하는 등의 최적화가 가능해진다. 둘째, 사용자 실수를 줄일 수 있다. 데이터를 실제로 처리하기 전까지는 아무런 클러스터 자원이 소모되지 않으므로, 논리적 오류가 있는 큰 규모의 작업을 실수로 제출하는 것을 방지하는 효과도 있다.
지연 실행 모델은 RDD의 불변성 특성과 밀접하게 연관되어 작동한다. RDD는 생성 후 변경할 수 없으므로, 각 변환 연산은 새로운 RDD를 생성하는 논리적 설명으로 기록된다. 이 기록된 변환들의 체인은 액션 연산이 호출되어 결과를 계산하거나 HDFS 같은 저장소에 저장해야 할 필요가 생겼을 때 비로소 물리적 실행 계획으로 변환되고 클러스터 매니저를 통해 익스큐터들에게 분배되어 실행된다.
이러한 설계는 맵리듀스와 같은 전통적인 배치 처리 시스템의 즉시 실행 모델과 대비된다. 지연 실행을 통해 Spark는 더 효율적인 리소스 활용과 향상된 성능 최적화를 달성할 수 있으며, 이는 대규모 데이터 처리 작업에서 매우 중요한 장점으로 작용한다.
3.4. 스케줄링
3.4. 스케줄링
스파크 코어의 스케줄링은 클러스터 자원을 효율적으로 할당하고 작업을 실행하는 핵심 메커니즘이다. 이는 드라이버 프로그램 내의 DAG 스케줄러와 태스크 스케줄러를 통해 이루어진다. 사용자가 코드에서 액션 연산을 호출하면, DAG 스케줄러는 RDD의 의존성 그래프를 분석하여 스테이지의 DAG를 생성한다. 각 스테이지는 셔플 의존성의 경계를 기준으로 나누어지며, 셔플이 없는 넓은 의존성 연산들은 동일한 스테이지로 묶인다.
생성된 스테이지는 태스크 스케줄러에 의해 실행된다. 태스크 스케줄러는 클러스터 매니저와 통신하여 각 스테이지를 구성하는 태스크들을 익스큐터에 분배한다. 스케줄링은 기본적으로 데이터 지역성을 고려하며, 데이터가 위치한 노드에서 태스크를 실행하려고 시도함으로써 네트워크 전송 비용을 최소화한다. 지연 실행 모델은 이러한 스케줄링 최적화를 가능하게 하는 기반이 된다.
스케줄링 정책은 클러스터 매니저의 종류에 따라 세부적으로 달라질 수 있다. 스파크는 스탠드얼론 모드, Apache Mesos, Hadoop YARN, Kubernetes 등 다양한 매니저 위에서 동작할 수 있다. 또한 FAIR 스케줄링과 같은 스케줄링 모드를 지원하여 여러 사용자나 애플리케이션 간에 자원을 공정하게 분배할 수 있도록 한다.
4. 프로그래밍 모델
4. 프로그래밍 모델
4.1. 변환 연산
4.1. 변환 연산
스파크 코어의 변환 연산은 RDD를 생성하거나 형태를 변환하는 지연 평가되는 연산이다. 이 연산들은 즉시 실행되지 않고, 새로운 RDD의 의존성 정보를 DAG에 기록한다. 대표적인 변환 연산으로는 데이터를 필터링하는 filter, 각 요소에 함수를 적용하는 map, 키-값 쌍을 기준으로 데이터를 그룹화하는 groupByKey 등이 있다.
변환 연산은 크게 넘로우 변환과 와이드 변환으로 구분된다. 넘로우 변환은 각 파티션이 독립적으로 처리되어 셔플이 발생하지 않는 연산으로, map과 filter가 대표적이다. 반면 와이드 변환은 여러 파티션의 데이터를 재분배해야 하므로 셔플이 발생하는 연산으로, groupByKey와 reduceByKey, join 등이 여기에 속한다. 와이드 변환은 네트워크 통신 비용이 크므로 성능에 더 큰 영향을 미친다.
이러한 변환 연산들은 액션 연산이 호출되어 결과가 실제로 필요해질 때까지 실행을 미루는 지연 실행 특성을 가진다. 이로 인해 스파크는 전체 연산 계획을 최적화하고, 불필요한 중간 결과물을 생성하지 않으며, 장애 발생 시 이 의존성 정보를 통해 손실된 파티션만 재계산하는 내결함성을 구현할 수 있다.
4.2. 액션 연산
4.2. 액션 연산
액션 연산은 RDD나 데이터프레임과 같은 분산 데이터셋에 대해 실제 계산을 수행하고 결과를 드라이버 프로그램으로 반환하거나 외부 저장소에 저장하는 연산이다. 변환 연산이 지연 실행되는 변환을 정의하는 데 그친다면, 액션 연산은 변환 연산으로 구성된 전체 연산 그래프를 실행하도록 트리거하는 역할을 한다. 이로써 스파크 코어의 지연 실행 모델이 완성된다.
주요 액션 연산으로는 데이터를 수집하는 collect(), 첫 번째 요소를 반환하는 first(), 요소의 개수를 세는 count(), 모든 요소를 집계하는 reduce(), 샘플을 추출하는 take(), 데이터를 외부 파일 시스템이나 데이터베이스에 저장하는 saveAsTextFile() 등이 있다. 이러한 연산이 호출되면 드라이버 프로그램은 클러스터 매니저를 통해 익스큐터들에게 작업을 할당하고, 각 익스큐터는 자신의 파티션에 저장된 데이터에 대해 지정된 계산을 수행한다.
액션 연산의 결과는 일반적으로 스칼라 컬렉션이나 파이썬 객체와 같은 단일 머신의 메모리에 담길 수 있는 크기로 반환된다. 따라서 매우 큰 데이터셋에 collect()를 사용하면 드라이버의 메모리 부족이 발생할 수 있어 주의가 필요하다. 대신 take()나 sample()을 사용하거나, 결과를 직접 HDFS나 아마존 S3와 같은 분산 저장소에 쓰는 방식을 고려한다.
액션 연산은 스파크 애플리케이션의 최종 출력을 생성하는 단계이므로, 애플리케이션의 성능과 결과 정확도에 직접적인 영향을 미친다. 효율적인 액션 연산 사용을 위해 불필요한 데이터 수집을 피하고, 캐싱과 적절한 파티셔닝을 통해 셔플 비용을 최소화하는 것이 중요하다.
5. 데이터 저장 및 입출력
5. 데이터 저장 및 입출력
스파크 코어는 다양한 데이터 소스와의 연동을 위한 풍부한 데이터 저장 및 입출력 기능을 제공한다. 이는 분산 파일 시스템인 HDFS, 아마존 S3, 로컬 파일 시스템과 같은 저장소로부터 데이터를 읽고 쓸 수 있도록 지원한다. 또한 Apache HBase, Apache Cassandra와 같은 NoSQL 데이터베이스, JDBC를 통해 접근 가능한 관계형 데이터베이스, Apache Hive의 데이터 웨어하우스와도 통합된다. 이러한 광범위한 호환성 덕분에 사용자는 기존 데이터 인프라를 크게 변경하지 않고도 스파크를 도입할 수 있다.
데이터 입출력의 핵심은 RDD와 DataFrame API를 통한 추상화에 있다. 사용자는 textFile(), saveAsTextFile(), sequenceFile()과 같은 메서드를 사용해 텍스트 파일, 시퀀스 파일, 객체 파일 등 다양한 형식의 데이터를 손쉽게 로드하거나 저장할 수 있다. 특히 Parquet, ORC, JSON, CSV와 같은 구조화된 데이터 포맷에 대한 네이티브 지원이 강화되어 있으며, 사용자 정의 포맷을 위한 확장 인터페이스도 제공된다.
입출력 성능 최적화를 위해 스파크는 데이터 로컬리티를 고려한 스케줄링과 압축 기능을 활용한다. 데이터가 저장된 위치에서 가까운 익스큐터에서 작업을 실행함으로써 네트워크 오버헤드를 줄이고, 디스크 공간과 직렬화 비용을 절감하기 위해 데이터를 압축하여 읽고 쓸 수 있다. 이는 대규모 데이터 처리 시 전체 작업 시간을 단축하는 데 기여한다.
6. 성능 최적화
6. 성능 최적화
6.1. 캐싱
6.1. 캐싱
스파크 코어의 캐싱은 메모리 내 연산 성능을 극대화하는 핵심 메커니즘이다. RDD나 데이터프레임과 같은 데이터셋을 클러스터의 메모리나 디스크에 지속적으로 저장하여, 동일한 데이터셋에 대한 반복적인 연산 시 매번 처음부터 재계산하는 것을 방지한다. 이는 특히 머신러닝 알고리즘의 반복 학습이나 대화형 데이터 분석과 같이 동일한 데이터에 여러 번의 연산이 수행되는 작업에서 성능 향상 효과가 두드러진다.
사용자는 persist() 또는 cache() 메서드를 호출하여 특정 RDD에 대한 캐싱을 명시적으로 지시할 수 있다. cache()는 기본 저장 수준인 메모리 저장을 사용하는 반면, persist()는 사용자가 저장 수준을 세밀하게 제어할 수 있도록 한다. 지원되는 주요 저장 수준은 다음과 같다.
저장 수준 | 설명 |
|---|---|
MEMORY_ONLY | |
MEMORY_AND_DISK | 메모리에 저장하되, 용량이 부족하면 디스크에 나머지 저장. |
DISK_ONLY | RDD를 디스크에만 저장. |
MEMORY_ONLY_SER | RDD를 직렬화된 바이트 배열 형태로 메모리에 저장. |
MEMORY_AND_DISK_SER | 직렬화된 형태로 저장하며, 메모리 부족 시 디스크 사용. |
캐싱은 지연 실행 모델 하에서 작동한다. persist()를 호출하는 시점에는 실제 캐싱이 발생하지 않으며, 해당 RDD를 계산하게 하는 첫 번째 액션 연산이 실행될 때 비로소 데이터가 지정된 저장 수준에 따라 캐시된다. 이후 같은 RDD에서 파생된 다른 연산들은 캐시된 데이터를 재사용하게 되어 처리 속도가 크게 개선된다. 스파크의 내결함성은 캐시된 데이터에도 적용되어, 일부 파티션을 잃어버리면 원본 RDD의 변환 연산 계보를 통해 자동으로 재계산하여 복구한다.
6.2. 파티셔닝
6.2. 파티셔닝
파티셔닝은 스파크 코어에서 데이터를 여러 물리적 청크로 나누어 클러스터의 여러 노드에 분산 저장하고 처리하는 핵심 메커니즘이다. RDD나 데이터프레임과 같은 데이터 구조는 기본적으로 여러 파티션으로 구성되며, 각 파티션은 익스큐터에서 독립적으로 연산될 수 있는 작업의 기본 단위가 된다. 적절한 파티셔닝은 데이터의 균등한 분배를 보장하고, 데이터 스큐를 방지하며, 병렬 처리의 효율성을 극대화하여 전체 작업 성능을 결정짓는 중요한 요소이다.
스파크는 다양한 파티셔닝 전략을 제공한다. 기본적으로 데이터를 읽을 때나 변환 연산을 수행할 때 해시 파티셔닝이나 라운드 로빈 파티셔닝이 자동으로 적용된다. 개발자는 repartition()이나 coalesce() 같은 메서드를 사용해 파티션 수를 명시적으로 조정하거나, partitionBy()를 사용해 특정 칼럼 기준으로 커스텀 파티셔너를 정의할 수 있다. 특히 조인이나 그룹화 연산 전에 관련 데이터를 동일한 파티셔너로 미리 파티셔닝해 두면 셔플 과정에서 발생하는 네트워크 비용을 크게 줄일 수 있다.
파티셔닝의 효과는 데이터의 특성과 수행할 연산에 따라 달라진다. 파티션 수가 너무 적으면 병렬성이 저하되고 메모리 부족 오류가 발생할 수 있으며, 반대로 파티션 수가 너무 많으면 작업 스케줄링과 태스크 관리의 오버헤드가 증가한다. 따라서 데이터 크기, 클러스터의 코어 수, 사용 가능한 메모리 등을 고려하여 최적의 파티션 수를 찾는 튜닝이 필요하다. 스파크 코어의 스케줄링과 성능 최적화는 이러한 파티셔닝 전략과 깊이 연관되어 있다.
6.3. 브로드캐스트 변수
6.3. 브로드캐스트 변수
스파크 코어의 브로드캐스트 변수는 클러스터의 모든 노드에 효율적으로 큰 읽기 전용 변수를 배포하기 위한 메커니즘이다. 이 변수는 드라이버 프로그램에서 생성되며, 익스큐터에서 실행되는 태스크들이 공통으로 참조해야 하는 대용량의 데이터(예: 참조 테이블, 머신러닝 모델 가중치, 설정 파일 내용 등)를 캐싱할 때 유용하다. 브로드캐스트 변수를 사용하지 않으면 각 태스크가 독립적으로 해당 데이터를 드라이버로부터 가져와야 하므로 네트워크 오버헤드가 크게 증가하고 성능이 저하될 수 있다.
브로드캐스트 변수의 동작 방식은 분산 시스템에서 효율적인 데이터 공유를 보장한다. 드라이버는 변수 값을 직렬화하여 클러스터 매니저를 통해 각 워커 노드에 한 번만 전송한다. 각 워커 노드는 수신한 값을 역직렬화하여 메모리에 저장하고, 해당 노드에서 실행되는 모든 태스크는 이 로컬 복사본을 공유하여 접근한다. 이는 네트워크를 통한 데이터 전송을 최소화하고, 각 태스크의 실행 속도를 향상시키는 데 기여한다.
주요 프로그래밍 인터페이스로는 SparkContext.broadcast() 메서드를 통해 변수를 생성하고, 익스큐터 코드 내에서는 브로드캐스트 변수의 .value 속성을 통해 캐시된 데이터에 접근한다. 사용이 완료된 브로드캐스트 변수는 .unpersist() 메서드를 호출하여 메모리에서 명시적으로 제거하거나, 드라이버 프로그램이 종료될 때 자동으로 해제할 수 있다. 이 메커니즘은 내결함성을 갖추고 있어, 노드에 장애가 발생하더라도 필요한 경우 데이터를 재전송하여 복구할 수 있다.
6.4. 어큐뮬레이터
6.4. 어큐뮬레이터
어큐뮬레이터는 스파크 코어에서 제공하는 공유 변수 중 하나로, 클러스터의 여러 익스큐터에서 실행되는 태스크들이 정보를 누적하여 집계할 수 있도록 설계된 변수이다. 주로 카운터나 합계를 계산하는 데 사용되며, 드라이버 프로그램에서만 그 값을 읽을 수 있고, 익스큐터에서는 값을 누적하는 연산만 수행할 수 있다. 이는 분산 컴퓨팅 환경에서 안전하게 전역 상태를 관리하기 위한 메커니즘이다.
어큐뮬레이터는 스파크 컨텍스트를 통해 생성되며, 기본적으로 숫자 타입을 지원한다. 사용자는 정수나 실수형의 어큐뮬레이터를 만들어 각 태스크에서 발생하는 이벤트 수나 특정 값의 합을 효율적으로 수집할 수 있다. 이는 맵리듀스 패러다임에서 카운터를 사용하는 방식과 유사하지만, 스파크의 RDD 기반 연산 내에서 더욱 통합적으로 활용된다.
어큐뮬레이터의 중요한 특징은 지연 실행 모델과의 호환성이다. 액션 연산이 실행될 때 각 태스크의 업데이트가 드라이버로 전송되어 최종 값이 결정된다. 이 과정은 내결함성을 보장하며, 태스크가 재실행되더라도 어큐뮬레이터의 업데이트는 한 번만 적용되도록 설계되어 정확성을 유지한다.
사용자 정의 어큐뮬레이터를 구현하여 더 복잡한 누적 로직을 지원할 수도 있다. 이를 통해 분산 시스템에서의 모니터링, 디버깅, 또는 간단한 통계 수집을 효율적으로 수행할 수 있으며, 브로드캐스트 변수와 함께 스파크의 공유 변수 기능을 구성하는 핵심 요소이다.
7. 배포 및 실행
7. 배포 및 실행
스파크 코어는 다양한 환경에서 배포되고 실행될 수 있도록 설계되었다. 기본적으로 스파크는 독립 실행형 클러스터 모드로 배포될 수 있으며, 이 경우 자체 내장된 클러스터 매니저를 사용한다. 그러나 더 널리 사용되는 방식은 하둡 YARN이나 메소스, 쿠버네티스와 같은 외부 클러스터 관리자를 활용하는 것이다. 특히 YARN은 기존 하둡 인프라와의 통합이 용이하여 많은 기업 환경에서 선호되는 옵션이다.
실행 측면에서 스파크 애플리케이션은 spark-submit이라는 명령줄 도구를 통해 제출된다. 이 도구는 사용자가 애플리케이션 JAR 파일이나 Python 스크립트, 필요한 라이브러리, 실행에 필요한 메모리 및 코어 수 등의 구성을 지정하여 클러스터에 제출할 수 있게 해준다. 드라이버 프로그램은 제출된 애플리케이션의 메인 함수를 실행하며, 클러스터 매니저로부터 자원을 할당받아 익스큐터 프로세스를 여러 워커 노드에 분산시켜 구동한다.
로컬 머신에서의 개발 및 테스트를 위해 스파크는 로컬 모드도 지원한다. 이 모드에서는 모든 컴퓨팅이 단일 머신의 여러 스레드에서 실행되며, 별도의 클러스터 설정 없이 애플리케이션 로직을 빠르게 검증할 수 있다. 또한 스파크 셸 (Spark Shell)을 제공하여 대화형으로 스칼라나 Python 코드를 실행하고 즉각적인 결과를 확인할 수 있도록 한다.
클라우드 환경에서는 아마존 EMR, 데이터브릭스, 구글 클라우드 데이터프록, 마이크로소프트 애저 HDInsight와 같은 관리형 서비스를 통해 스파크 클러스터를 쉽게 프로비저닝하고 실행할 수 있다. 이러한 서비스들은 클러스터 설정, 확장, 모니터링의 복잡성을 대부분 추상화하여 사용자가 애플리케이션 개발에 집중할 수 있게 한다.
