Blog
pysparksparkspark-uidebuggingperformancedata-engineering

PySpark 느린 잡 디버깅 — Spark UI와 DAG 읽는 법

"느린데 어디가 느린지 모르겠다"를 끝내는 가이드. Spark UI 의 Jobs·Stages·Tasks·SQL 탭을 읽어 스큐·스필·잘못된 조인·셔플 폭발을 식별하고, EXPLAIN 으로 실행 계획을 진단하는 절차를 정리합니다.

Data Dynamics2026年6月5日9 min read
This post is not yet translated. The original Korean version is shown below.

"잡이 느린데 어디가 느린지 모르겠다." 데이터 엔지니어가 가장 자주 하는 말입니다. 무작정 executor.memory 를 올리거나 파티션 수를 바꿔보는 추측성 튜닝은 시간만 낭비합니다. Spark UI 를 읽을 줄 알면, 느린 원인을 5분 안에 짚어낼 수 있습니다.

이 글은 Spark UI 의 각 탭을 어떻게 읽는지, 어떤 숫자가 무슨 문제를 가리키는지, 그리고 느린 잡을 진단하는 순서를 정리합니다.

1. 진단의 출발 — 위에서 아래로

Spark UI 는 계층 구조입니다. 위에서 아래로 좁혀 들어갑니다.

Jobs (전체 잡)
  └─ Stages (셔플 경계로 나뉜 단계)
        └─ Tasks (스테이지 안의 병렬 단위)   ← 대부분의 진실이 여기 있음
SQL / DataFrame 탭 (논리/물리 계획 + 실측)
답하는 질문
Jobs어떤 잡/액션이 오래 걸리나
Stages어느 스테이지가 병목인가
Tasks스큐·스필이 있나 (핵심)
SQL조인 방식·셔플·스캔이 적절한가
Executors자원·GC·실패가 정상인가

2. Stages 탭 — 병목 스테이지 찾기

오래 걸리는 잡을 클릭해 스테이지로 들어가면, 각 스테이지의 소요 시간과 셔플 양이 보입니다.

확인할 것:

  • Duration 이 압도적으로 긴 스테이지 → 병목.
  • Shuffle Read / Write 가 큰 스테이지 → 셔플이 비용의 핵심.
  • Input / Output → 데이터가 어디서 들어오고 나가나.

셔플(Shuffle Read/Write)이 큰 스테이지가 보이면, 거기서 조인·groupBy 가 데이터를 대량으로 재분배하고 있다는 뜻입니다. 셔플은 네트워크·디스크를 쓰므로 잡 시간의 대부분을 차지하는 경우가 많습니다.

3. Tasks 탭 — 가장 중요한 진실

스테이지를 클릭해 Summary Metrics(태스크 분위수 통계) 를 봅니다. 여기서 대부분의 문제가 드러납니다.

스큐 식별

Metric          Min    25th   Median  75th   Max
Duration        2s     3s     3s      4s     8min   ← Max 가 Median 의 160배!
Shuffle Read    50MB   52MB   51MB    53MB   9GB    ← 한 태스크만 거대

Max 가 Median 의 수십~수백 배라면 데이터 스큐입니다. 소수 태스크가 전체를 끌고 있습니다. (해결은 별도 글 "PySpark 데이터 스큐 완전 정복".)

스필 식별

Spill (Memory)  /  Spill (Disk)  컬럼에 큰 값
→ execution 메모리 부족으로 디스크로 흘리는 중 → 느림

Spill 이 크면 메모리가 빠듯하다는 신호입니다. 파티션을 잘게 하거나 메모리를 확보하세요(별도 글 "PySpark Executor OOM 정복").

태스크 신호의미대응
Max ≫ Median (Duration)스큐salt/broadcast
Spill 큼메모리 부족파티션↑, 캐시↓
GC Time 큼힙 압박힙·객체 조정
태스크 수가 200 고정기본 셔플 파티션shuffle.partitions 조정/AQE

4. SQL 탭 — 실행 계획과 실측

DataFrame/SQL 잡은 SQL 탭에 쿼리별 실행 그래프가 그려지고, 각 노드에 실제 행 수·시간이 붙습니다. 가장 강력한 진단 화면입니다.

확인 포인트:

  • 조인 방식: BroadcastHashJoin(작은 쪽 복제) vs SortMergeJoin(양쪽 셔플). 작은 테이블인데 SMJ 면 broadcast 가 안 된 것 — 셔플 낭비.
  • Exchange(셔플) 노드 수: 많을수록 재분배 비용↑.
  • number of output rows: 어느 노드에서 행이 폭증하는지(조인 부풀림).
  • Scan 노드의 필터/프루닝: pushdown·파티션 프루닝이 됐는지.
== Exchange(셔플)가 많고, 작은 테이블이 SortMergeJoin 으로 처리됨
→ broadcast 임계값을 올리거나 broadcast() 힌트로 셔플 제거

5. EXPLAIN 으로 계획 확인

UI 없이 코드에서 바로 계획을 봅니다.

df.explain(mode="formatted")    # 읽기 좋은 포맷
# 또는
df.explain(True)                # 논리/최적화/물리 계획 모두

핵심 키워드:

키워드의미
BroadcastHashJoin작은 쪽 복제 조인(좋음, 셔플 없음)
SortMergeJoin양쪽 셔플 조인(큰 테이블끼리면 정상)
Exchange셔플 발생 지점
*(n) (codegen)Whole-Stage CodeGen 단계
PartitionFilters / PushedFilters프루닝·pushdown 동작

PushedFilters 가 비어 있으면 필터가 소스로 안 내려간 것입니다 — WHERE 절의 함수 래핑을 의심하세요.

6. AQE 확인 — 런타임 적응

AQE 가 켜져 있으면(spark.sql.adaptive.enabled=true), SQL 탭의 계획이 런타임에 바뀝니다(AdaptiveSparkPlan). 스큐 조인 분할·파티션 병합이 적용됐는지 여기서 확인할 수 있습니다.

spark.conf.set("spark.sql.adaptive.enabled", "true")
# UI SQL 탭에서 AdaptiveSparkPlan, coalesced/skew 표시 확인

7. Executors 탭 — 자원과 실패

확인신호
Failed Tasks재시도·OOM 반복
GC Time 비율높으면 힙 압박
Storage Memory캐시가 메모리 점유
Active/Dead익스큐터가 죽고 있나

GC Time 이 태스크 시간의 상당 비율이면 힙이 과대하거나 객체가 너무 많은 것입니다.

8. 진단 절차 (권장 순서)

1. Jobs/Stages → 가장 오래 걸린 스테이지 식별

2. Tasks Summary → Max vs Median 비교
        ├─ Max ≫ Median → 스큐 (salt/broadcast)
        ├─ Spill 큼     → 메모리 (파티션↑)
        └─ GC 큼        → 힙 조정

3. SQL 탭/EXPLAIN → 조인 방식·셔플·프루닝 점검
        ├─ 작은 테이블 SMJ → broadcast
        ├─ Exchange 과다  → 셔플 줄이기(버킷팅/사전집계)
        └─ PushedFilters 빔 → WHERE 함수 래핑 제거

4. Executors → 실패·GC·자원 확인

9. 증상 → 화면 → 처방

증상어디서 보나처방
한 태스크만 안 끝남Tasks: Max Duration스큐 해결
잡이 전반적으로 느림Stages: Shuffle 크기셔플 줄이기(버킷팅·사전집계)
간헐적 OOMTasks: Spill / Executors: GC파티션↑, 메모리 점검
조인이 느림SQL: 조인 노드broadcast 유도
스캔이 느림SQL: Scan PushedFilters프루닝·pushdown 복구
태스크가 너무 많음/적음Stages: task 수shuffle.partitions/AQE

10. 정리

핵심 지표잡아내는 문제
StagesShuffle Read/Write셔플 병목
TasksMax vs Median, Spill스큐, 메모리
SQL조인 방식, Exchange잘못된 조인, 셔플
EXPLAINPushedFilters프루닝 깨짐
ExecutorsGC, Failed자원·안정성

느린 Spark 잡 디버깅의 핵심은 "추측하지 말고 Spark UI 를 읽는 것"입니다. Stages 에서 병목 스테이지를, Tasks 에서 스큐·스필을, SQL 탭에서 잘못된 조인을 짚는 절차만 손에 익히면, 대부분의 성능 문제는 5분 안에 원인이 드러납니다. 이 진단 능력이 있어야 앞선 글들에서 다룬 스큐·메모리·조인 튜닝을 "어디에" 적용할지 알 수 있습니다.


이 글은 Spark 3.5 기준으로 작성되었습니다. 느린 Spark 잡 진단·튜닝이나 운영 모니터링 체계 수립이 필요하시면 언제든 문의해 주세요.

— Data Dynamics 엔지니어링 팀