✅ 스파크의 기본 아키텍처
컴퓨터 클러스터는 여러 컴퓨터의 자원을 모아 하나의 컴퓨터처럼 사용할 수 있게 만든다. 이 클러스터에서 작업을 조율할 수 있는 프레임워크가 바로 스파크이다. 스파크는 클러스터의 데이터 처리 작업을 관리하고 조율한다.
스파크가 연산에 사용할 클러스터는 스파크 스탠드얼론 클러스터 매니저, 하둡 YARN, 메소스 같은 클러스터 매니저에서 관리한다.
사용자가 클러스터 매니저에 스파크 애플리케이션을 제출하면, 이를 제출 받은 클러스터 매니저는 실행에 필요한 자원을 할당하고, 이 할당 받은 자원으로 작업을 처리하게 된다.
🍎 스파크 애플리케이션
스파크 애플리케이션은
- 드라이버 프로세스
- 스파크 애플리케이션 정보의 유지 관리
- 사용자 프로그램이나 입력에 대한 응답
- 전반적인 익스큐터 프로세스의 작업과 관련된 분석
- 배포 및 스케줄링 역할
- 다수의 익스큐터 프로세스
- 드라이버 프로세스가 할당한 작업을 수행
- 진행 상황을 다시 드라이버에 보고
로 구성된다.
스파크 애플리케이션의 아키텍처
- 스파크는 사용 가능한 자원을 파악하기 위해 클러스터 매니저를 사용한다.
- 드라이버 프로세스는 주어진 작업을 완료하기 위해 드라이버 프로그램의 명령을 익스큐터에서 실행할 책임이 있다.
- 익스큐터는 대부분 스파크 코드를 실행하는 역할을 하며, 드라이버는 스파크의 언어 API를 통해 다양한 언어로 실행할 수 있다.
✅ 스파크의 다양한 언어 API
- 스칼라
- 자바
- 파이썬
- SQL
- R
SparkSession과 스파크의 언어 API 간의 관계
스파크는 사용자를 대신해 팡선이나 R로 작성한 코드를 익스큐터의 JVM에서 실행할 수 있는 코드로 변환한다.
✅ 스파크 API
다양한 언어로 스파크를 사용할 수 있는 이유는 스파크가 기본적으로 두 가지 API를 제공하기 때문이다.
- 저수준의 비구조적 API
- 고수준의 구조적 API
🍊 SparkSession
- 스파크 애플리케이션은 SparkSession이라 불리는 드라이버 프로세스로 제어한다.
- SparkSession 인스턴스는 사용자가 정의한 처리 명령을 클러스터에서 실행한다.
- 하나의 SparkSession은 하나의 스파크 애플리케이션에 대응한다.
🪟 DataFrame
- 가장 대표적인 구조적 API
- 테이블의 데이터를 로우와 컬럼으로 표현
- 스키마: 컬럼과 컬럼의 타입을 정의한 목록
- 스파크 DataFrame은 수천 대의 컴퓨터에 분산되어 있다.
- 왜⁉️ → 단일 컴퓨터에 저장하기에는 데이터가 너무 크거나 계산이 너무 오래 걸릴 수 있기 때문
🗂️ 파티션
- 클러스터의 물리적 머신에 존재하는 로우의 집합
- 데이터가 컴퓨터 클러스터에 물리적으로 분산되는 방식
- 스파크는 모든 익스큐터가 병렬로 작업을 수행할 수 있도록 파티션이라 불리는 청크 단위로 데이터를 분할한다.
- 물리적 파티션에 데이터 변환용 함수를 지정하면 스파크가 실제 처리 방법을 결정
🤖 트랜스포메이션
- 스파크의 핵심 데이터 구조는 불변성(immutable)
- DataFrame을 변경하기 위해서는 변경 방법을 스파크에 알려줘야 하는데, 이때 사용하는 명령을 트랜스포메이션이라고 부른다.
예)
divisBy2 = myRange.where("number % 2 = 0")
- 위 코드는 추상적인 트랜스포메이션만 지정한 상태이기 때문에 액션을 호출하지 않으면 스파크는 실제 트랜스포메이션을 수행하지 않는다.
- 트랜스포메이션의 두 가지 유형
-
좁은 의존성 (파이프라이닝)
→ 각 입력 파티션이 하나의 출력 파티션에만 영향
-
넓은 의존성 (셔플)
→ 하나의 입력 파티션이 여러 출력 파티션에 영향
🕝 지연 연산
- 스파크가 연산 그래프를 처리하기 직전까지 기다리는 동작 방식
- 스파크는 특정 연산 명령이 내려진 즉시 데이터를 수정하지 않고 원시 데이터에 적용할 트랜스포메이션의 실행 계획을 생성한다.
- 스파크는 코드를 실행하는 마지막 순간까지 대기하다가 원형 DataFrame 트랜스포메이션을 간결한 물리적 실행 계획으로 컴파일한다.
🔥 이 과정은 전체 데이터 흐름을 최적화하는 엄청난 강점을 가지고 있다.
예) 조건절 푸시다운
원시 데이터에서 하나의 로우만 가져오는 필터
→ 이 필터를 데이터소스로 위임 (만약 데이터 저장소가 데이터베이스라면 where 절의 처리를 데이터베이스에 위임해서 스파크는 하나의 레코드만 받는다.)
→ 필요한 레코드 하나만 읽기! 처리에 필요한 자원을 최소화하며 최적화 가능
👊 액션
- 트랜스포메이션 → 논리적 실행 계획 / 액션 → 실제 연산 수행
- 일련의 트랜스포메이션으로부터 결과를 계산하도록 지시하는 명령
- 액션을 지정하면 스파크 잡이 시작된다
- 스파크 잡은 필터(좁은 트랜스포메이션)를 수행한 후 파티션 별로 레코드 수를 카운트(넓은 트랜스포메이션)한다. 그리고 각 언어에 적합한 네이티브 객체에 결과를 모은다.
📱 스파크 UI
- 스파크 잡의 진행 상황을 모니터링할 때 사용
- 4040번 포트
- 스파크 잡의 상태, 환경 설정, 클러스터 상태 등의 정보 확인 가능
🌟스파크 잡은 개별 액션에 의해 트리거되는 다수의 트랜스포메이션으로 이루어져 있으며 스파크 UI로 잡을 모니터링할 수 있다!!!🌟
[출처] 스파크 완벽 가이드 (빌 체임버스, 마테이 자하리아 지음)