← 학습 카테고리

Learn

Spark

38개 모듈 · 현재 27번째

Spark 모듈 27/38 spark-learn-27

70개 질문 블로그로 보는 추가 확인 사항 — 파티셔너와 튜닝 체크리스트

70 Spark Interview Questions for Data Engineers (Real Asks, 2026) — (블로그, 발행처 미상) 70 Spark Interview Questions for Data Engineers (전체 50문항 + FAQ)

이 모듈을 다 읽으면

  • spark.sql.shuffle.partitions(DataFrame/SQL 셔플 파티션 수 설정)와 HashPartitioner/RangePartitioner(RDD 파티셔너 클래스)가 서로 다른 층위의 개념임을 구분할 수 있다
  • Spark 성능 튜닝을 시작할 때 우선순위를 둘 6가지 레버를 순서대로 나열할 수 있다
  • 이 블로그가 기존 자료와 동일하게 반복하는 오류(브로드캐스트 조인 100MB, cache() 기본 레벨 혼동, executor.memoryOverhead 10%)를 이미 정정된 사실과 대조해 다시 판별할 수 있다

이 자료는 기존에 처리한 spark_ref_01.md 블로그(50문항)와 질문 순서만 다를 뿐 거의 동일한 내용(아키텍처, RDD/DataFrame, 셔플, Catalyst/Tungsten, 클러스터 매니저, 실전 코딩 시나리오)을 담고 있어, 이미 spark-blog-draft-01~05 모듈에서 정정까지 마친 부분은 중복 수록하지 않는다. 대신 이 자료의 FAQ 섹션에만 새로 등장한 두 가지 — 파티셔너 개념의 혼용, 성능 튜닝 우선순위 체크리스트 — 를 정리하고, 기존에 발견한 오류(브로드캐스트 조인 임계값, cache() 기본 레벨, memoryOverhead 계산식)가 이 블로그에도 동일하게 반복되고 있음을 재확인한다.

이미 다룬 내용과의 중복 — 무엇을 건너뛰었는가

이 블로그의 Q1~50은 spark_ref_01.md 블로그의 아키텍처(Driver/Executor/DAG), RDD/DataFrame/Dataset, narrow/wide 트랜스포메이션, 데이터 스큐, Catalyst 4단계, Project Tungsten, 클러스터 매니저 4종, checkpoint/lineage, reduceByKey vs groupByKey, UDF 비용 등과 주제와 설명 순서까지 거의 일치한다. 이미 spark-learn-22~26 모듈에서 각 주제를 정정까지 포함해 다뤘으므로 여기서는 재수록하지 않고, 그 모듈들을 참조하면 된다.

핵심 포인트

  • 동일 주제 반복 시 원문 그대로 베끼지 않고 이미 존재하는 학습 모듈을 참조하는 것이 원칙이다
  • 이 블로그가 제공하는 새로운 정보는 FAQ 섹션의 파티셔너 설명과 튜닝 체크리스트 정도다

셔플 파티션 개수(spark.sql.shuffle.partitions)와 파티셔너(Partitioner)는 다른 개념 — 보강

FAQ는 "Spark splits data into partitions ... By default it uses HashPartitioner (200 shuffle partitions)"처럼 두 개념을 한 문장에 섞어 설명하는데, 이는 서로 다른 층위를 뭉뚱그린 표현이다. HashPartitioner/RangePartitioner는 RDD API에서 키 기반 셔플(reduceByKey, join 등)이 레코드를 어느 파티션으로 보낼지 정하는 파티셔닝 전략(클래스)이고, 기본적으로 키 기반 연산은 HashPartitioner를, sortByKey는 RangePartitioner를 사용한다. 반면 spark.sql.shuffle.partitions(기본값 200)는 DataFrame/SQL API에서 셔플이 일어날 때 결과 파티션의 개수를 지정하는 설정값으로, RDD의 파티셔너 클래스 선택과는 별개의 설정이다. 두 개념을 같은 문장으로 뭉치면 "파티셔너를 HashPartitioner로 바꾸면 셔플 파티션 수도 바뀐다"처럼 잘못 이해하기 쉽다.

핵심 포인트

  • HashPartitioner/RangePartitioner는 RDD가 레코드를 파티션에 배치하는 전략 클래스다
  • spark.sql.shuffle.partitions(기본 200)는 DataFrame/SQL 셔플 결과 파티션 개수를 정하는 별개의 설정이다
  • 두 개념을 뭉뚱그리면 설정 하나만 바꿔서 파티셔닝 전략까지 바뀐다고 오해하기 쉽다

성능 튜닝 우선순위 체크리스트 — 보강

FAQ에 정리된 "top six levers"는 실전에서 튜닝을 시작할 때 점검 순서로 참고할 만하다: (1) AQE(Adaptive Query Execution) 활성화(3.2+ 기본값이므로 꺼져 있는지 먼저 확인), (2) 작은 테이블 브로드캐스트, (3) 반복 사용되는 DataFrame 캐싱, (4) 자주 필터링하는 컬럼 기준 파티셔닝, (5) wide 트랜스포메이션 대신 narrow로 대체 가능한지 확인(예: join 전에 필터를 먼저 적용), (6) 클러스터 크기보다 워커당 메모리를 늘리는 것이 종종 더 효과적임. 다만 이 순서는 일반적인 경험칙일 뿐, 실제 병목은 Spark UI의 Stages 탭에서 가장 느린 스테이지를 먼저 확인한 뒤 그에 맞는 레버를 골라야 한다.

핵심 포인트

  • AQE 활성화 확인 → 브로드캐스트 → 캐싱 → 파티셔닝 → wide/narrow 재검토 → 워커당 메모리 순으로 접근하는 것이 실전 체크리스트다
  • 체크리스트는 출발점일 뿐 실제 병목은 Spark UI Stages 탭에서 가장 느린 스테이지를 먼저 확인해야 한다

기존에 발견한 오류의 재확인

이 블로그의 본문(Q24, Q25, Q39)도 이전 블로그와 동일한 방식으로 서로 모순되거나 부정확한 수치를 담고 있었다. cache()는 "기본 저장 레벨(Memory only)"이라고 본문에 적혀 있지만 FAQ는 "cache()는 persist(MEMORY_AND_DISK)의 축약형"이라고 설명해 자기모순이며, 실제로는 DataFrame/Dataset.cache()의 기본값이 MEMORY_AND_DISK가 맞다(RDD.cache()만 MEMORY_ONLY). 브로드캐스트 조인 임계값도 본문은 "보통 100MB 미만"이라 적었지만 FAQ는 정확히 "spark.sql.autoBroadcastJoinThreshold 기본값 10MB"라고 밝혀, 여기서도 기본값은 10MB가 맞고 100MB는 늘려 쓰는 실무 설정값일 뿐임을 재확인했다. spark.executor.memoryOverhead도 "실행자 메모리의 약 10%"라고만 적어, executorMemory*0.10과 최솟값 384MB 중 큰 값이라는 정확한 계산식은 여전히 빠져 있다.

핵심 포인트

  • cache() 기본 저장 레벨은 RDD가 MEMORY_ONLY, DataFrame/Dataset이 MEMORY_AND_DISK로 서로 다르다는 정정이 이 블로그에도 그대로 적용된다
  • spark.sql.autoBroadcastJoinThreshold의 기본값은 10MB이고 100MB는 실무에서 늘려 쓰는 값일 뿐이다
  • executor.memoryOverhead 기본값은 executorMemory*0.10과 384MB 중 큰 값이며 "10%"만으로는 소규모 executor에서 틀릴 수 있다