Apache Spark Reference
Spark 빅데이터 처리 레퍼런스
Apache Spark Reference 소개
Apache Spark 레퍼런스는 분산 데이터 처리를 위한 전체 Spark 생태계를 다루는 검색 가능한 빠른 참조입니다. parallelize, map, filter, reduceByKey 같은 RDD 연산과 함께 CSV/Parquet 파일 읽기, 컬럼 선택, 행 필터링, 조인 수행, 파티션 분할 출력 등을 위한 고수준 DataFrame API를 포함합니다. 각 항목은 Spark 애플리케이션에 바로 활용할 수 있는 실용적인 Scala 코드 예제를 제공합니다.
핵심 데이터 처리 외에도 createOrReplaceTempView를 활용한 Spark SQL, Hive 테이블 생성, RANK() OVER PARTITION BY 같은 윈도우 함수, 사용자 정의 함수(UDF) 등록을 다룹니다. 구조적 스트리밍 섹션에서는 Kafka 소스 읽기, 트리거 및 출력 모드 설정, 지연 데이터 처리를 위한 워터마크 적용, foreachBatch를 활용한 커스텀 마이크로 배치 처리 로직을 설명합니다.
이 레퍼런스는 VectorAssembler를 활용한 피처 엔지니어링, 분류를 위한 LogisticRegression, 다단계 ML 워크플로를 구성하는 Pipeline 등 MLlib 머신러닝 항목도 포함합니다. 설정 섹션에서는 셔플 파티션, 실행자 메모리 설정, StorageLevel을 활용한 캐시/persist 전략, 파티션 관리를 위한 repartition/coalesce, YARN 클러스터에 애플리케이션을 배포하는 spark-submit 명령어 등 필수 튜닝 파라미터를 다룹니다.
주요 기능
- parallelize, textFile, map, filter, reduceByKey를 포함한 RDD 생성 및 변환 연산
- 스키마 추론, 컬럼 선택, 필터링, groupBy, 조인을 지원하는 DataFrame API의 CSV/Parquet 입출력
- 임시 뷰, Hive 테이블 DDL, 윈도우 함수(RANK, PARTITION BY), UDF 등록을 포함한 Spark SQL
- Kafka 소스, 워터마크 기반 지연 데이터 처리, foreachBatch를 활용한 구조적 스트리밍
- VectorAssembler, LogisticRegression, 다단계 Pipeline을 활용한 MLlib 머신러닝 파이프라인
- cache/persist, repartition/coalesce, 셔플 파티션 설정을 통한 성능 튜닝
- YARN 클러스터 모드, 실행자 메모리, 코어 할당이 포함된 spark-submit 명령어 예제
- 옵션, 모드, 파티션 전략이 포함된 각 API의 실용적인 Scala 코드 예제
자주 묻는 질문
Spark에서 RDD와 DataFrame의 차이점은 무엇인가요?
RDD(Resilient Distributed Datasets)는 데이터 분산과 변환에 대한 세밀한 제어를 제공하는 저수준 API입니다. DataFrame은 데이터베이스 테이블과 유사하게 이름이 있는 컬럼으로 구성된 고수준 추상화입니다. DataFrame은 Catalyst 옵티마이저와 Tungsten 실행 엔진의 혜택을 받아 대부분의 워크로드에서 RDD보다 훨씬 빠릅니다. 파티셔닝에 대한 저수준 제어나 비정형 데이터가 필요하지 않다면 DataFrame을 사용하세요.
reduceByKey와 groupByKey는 어떻게 다른가요?
reduceByKey는 셔플 전에 각 파티션에서 동일 키의 값을 로컬로 먼저 결합하여 네트워크로 전송되는 데이터량을 줄입니다. groupByKey는 모든 키-값 쌍을 먼저 셔플한 후 그룹화하므로 대용량 데이터셋에서 메모리 문제를 일으킬 수 있습니다. 집계 작업에는 항상 groupByKey보다 reduceByKey나 aggregateByKey를 선호하세요. 일반적으로 2-10배 더 빠릅니다.
Spark 구조적 스트리밍에서 워터마크란 무엇인가요?
워터마크는 윈도우 집계에 포함될 수 있는 데이터의 최대 지연 임계값을 정의합니다. 예를 들어 withWatermark("timestamp", "10 minutes")는 Spark에게 지연 이벤트를 최대 10분간 기다리도록 지시합니다. 워터마크 이후에 도착하는 데이터는 삭제됩니다. 이를 통해 Spark는 오래된 상태를 정리하고 장시간 실행되는 스트리밍 쿼리에서 무한한 메모리 증가를 방지할 수 있습니다.
Spark에서 cache()와 persist()는 언제 사용해야 하나요?
cache()는 메모리에만 데이터를 저장합니다(persist(StorageLevel.MEMORY_ONLY)와 동일). persist()는 MEMORY_ONLY, MEMORY_AND_DISK, DISK_ONLY 또는 직렬화 변형 등 저장 수준을 선택할 수 있습니다. 메모리에 맞고 여러 번 재사용되는 데이터에는 cache()를 사용하세요. 데이터가 메모리에 완전히 맞지 않을 수 있을 때는 persist(MEMORY_AND_DISK)를 사용하여 오버플로가 재계산 대신 디스크로 넘치도록 하세요.
repartition()과 coalesce()의 차이점은 무엇인가요?
repartition(n)은 전체 셔플을 수행하여 정확히 n개의 파티션을 생성하며 파티션 수를 늘리거나 줄일 수 있습니다. coalesce(n)은 전체 셔플 없이 기존 파티션을 결합하여 파티션만 줄이므로 훨씬 효율적입니다. 파티션을 줄일 때(예: 단일 출력 파일 작성 전)는 coalesce를, 파티션을 늘리거나 컬럼 기준으로 데이터를 재분배할 때는 repartition을 사용하세요.
Spark SQL에서 UDF를 등록하고 사용하는 방법은?
spark.udf.register("funcName", (input: Type) => transformation)으로 UDF를 등록합니다. 등록 후 SQL 쿼리에서 사용할 수 있습니다: spark.sql("SELECT funcName(column) FROM table"). DataFrame API에서는 udf()를 사용하여 Column 함수를 생성합니다. UDF는 Catalyst 옵티마이저에 블랙박스이므로 특정 최적화를 방해합니다. 가능하면 내장 함수를 선호하세요.
구조적 스트리밍에서 사용 가능한 출력 모드는 무엇인가요?
Spark는 세 가지 출력 모드를 제공합니다. "append"는 마지막 트리거 이후 새 행만 쓰며, 집계 없는 쿼리나 워터마크가 있는 집계에서 작동합니다. "complete"는 매 트리거마다 전체 결과 테이블을 다시 쓰며, 워터마크 없는 집계에 필요합니다. "update"는 마지막 트리거 이후 변경된 행만 씁니다. 쿼리 유형과 다운스트림 싱크 요구사항에 따라 선택하세요.
YARN 클러스터용 spark-submit을 어떻게 설정하나요?
프로덕션 배포에는 --master yarn --deploy-mode cluster를 사용합니다. 주요 파라미터로는 --num-executors(실행자 컨테이너 수), --executor-memory(실행자당 RAM, 예: 4g), --executor-cores(실행자당 CPU 코어), --driver-memory가 있습니다. 동적 할당을 위해서는 실행자 수를 고정하는 대신 spark.dynamicAllocation.enabled=true를 설정하세요. 디버깅이 쉬운 --deploy-mode client로 먼저 테스트하세요.