Spark UI: глубокое погружение
Spark UI — ваш главный инструмент диагностики. Каждое Spark-приложение запускает веб-интерфейс на порту 4040, где вы видите всё: от общей картины jobs до деталей каждой task. Проблема в том, что UI показывает сотни метрик — нужно знать, на что смотреть.
В этом уроке мы разберём каждую вкладку Spark UI и научимся находить красные флаги — признаки проблем, которые убивают производительность.
Jobs Tab: общая картина
Вкладка Jobs показывает все jobs приложения. Каждый action (count, collect, write) создаёт отдельный job.
Что искать:
- Duration — сколько времени занял каждый job. Если один job в 10 раз дольше остальных, это сигнал
- Stages — количество stages в job. Много stages = много shuffles
- Failed jobs — красная строка означает exception. Кликните для stack trace
Job ID | Description | Duration | Stages | Status
-------|------------------|----------|---------|--------
0 | count at <...> | 2.1 s | 2/2 | SUCCEEDED
1 | save at <...> | 45.3 s | 5/5 | SUCCEEDED ← подозрительно долго
2 | collect at <...> | -- | 0/3 | FAILED ← красный флаг
Красный флаг: один job значительно дольше остальных
Если Job 1 занимает 45 секунд при том, что Job 0 — 2 секунды, проверьте его stages. Скорее всего, одна из stages содержит data skew или excessive shuffle.
Stages Tab: где тратится время
Вкладка Stages — самая информативная. Здесь вы видите детали каждой stage: количество tasks, shuffle read/write, GC time, task duration distribution.
Ключевые колонки:
| Метрика | Что показывает | Красный флаг |
|---|---|---|
| Duration | Время выполнения stage | > 5 минут для одной stage |
| Input | Объём прочитанных данных | Неожиданно большой (нет partition pruning?) |
| Shuffle Read | Данные полученные из других stages | > 1 GB на stage |
| Shuffle Write | Данные отправленные в другие stages | >> Shuffle Read (data explosion) |
| GC Time | Время сборки мусора | > 10% от Duration |
Task Duration Distribution
Внутри каждой stage кликните на Event Timeline или Summary Metrics. Вы увидите распределение task durations:
Metric | Min | 25th | Median | 75th | Max
----------------|--------|--------|--------|--------|--------
Duration | 0.1 s | 0.3 s | 0.4 s | 0.5 s | 45.2 s ← SKEW!
GC Time | 0 ms | 5 ms | 12 ms | 20 ms | 8.5 s ← SKEW!
Shuffle Read | 1 MB | 2 MB | 2 MB | 3 MB | 450 MB ← SKEW!
Красный флаг: Max >> Median в task metrics
Когда максимальная task duration в 100 раз больше медианы (45.2s vs 0.4s), это data skew. Одна партиция содержит значительно больше данных, чем остальные. Решение: salting, AQE skew join, или repartition.
GC Time: скрытый убийца
GC Time > 10% от task duration — серьёзный сигнал. Это означает, что executor тратит больше времени на сборку мусора, чем на полезную работу.
Причины высокого GC:
- Слишком мало памяти для executor (
spark.executor.memory) - Слишком много данных в одной partition
- Cache/persist занимает слишком много storage memory
- Утечка объектов через UDF
Что делать:
# Увеличить память executor
spark.conf.set("spark.executor.memory", "4g")
# Или увеличить количество партиций (меньше данных на task)
df = df.repartition(200)
SQL Tab: план запроса
Вкладка SQL доступна для DataFrame/SQL операций и показывает визуальный план выполнения с метриками на каждом узле.
Что искать:
- Scan: количество прочитанных строк. Если нет predicate pushdown — сканируете всю таблицу
- Filter: количество строк до и после фильтрации. Ratio 1000:1 = фильтр работает поздно
- Exchange: это shuffle. Количество байт показывает объём перемещённых данных
- SortMergeJoin vs BroadcastHashJoin: broadcast = быстро, sort-merge = shuffle
+- WholeStageCodegen (3)
+- SortMergeJoin [customer_id], [customer_id]
:- Exchange hashpartitioning(customer_id, 200) ← 2.3 GB shuffle!
: +- Filter (amount > 100)
: +- Scan parquet [orders] (1.2B rows) ← нет partition pruning
+- Exchange hashpartitioning(customer_id, 200) ← 450 MB shuffle
+- Scan parquet [customers] (10M rows) ← можно broadcast!
В этом примере:
- customers (450 MB) достаточно мала для broadcast join (по умолчанию < 10 MB, но можно увеличить)
- orders сканирует 1.2B строк — нужен partition pruning по дате
- Два Exchange = два shuffle по 2.3 GB + 450 MB
Storage Tab: кэширование
Вкладка Storage показывает все кэшированные (persist/cache) DataFrame и RDD.
Что искать:
- Size in Memory / Size on Disk — сколько памяти занимает кэш
- Fraction Cached — если < 100%, часть данных вытеснена из памяти (spill)
- Storage Level — MEMORY_ONLY vs MEMORY_AND_DISK
Распределение памяти executor:
Время обработки:
Наведите: как работает spark.memory.fraction
Анти-паттерн: кэширование всего подряд
Кэширование занимает storage memory, вытесняя execution memory. Кэшируйте только те DataFrame, которые используются более одного раза. Используйте df.unpersist() когда кэш больше не нужен.
Environment Tab: конфигурация
Вкладка Environment показывает все активные конфигурации Spark. Здесь можно проверить:
spark.sql.adaptive.enabled— включён ли AQEspark.sql.shuffle.partitions— количество shuffle partitions (по умолчанию 200)spark.executor.memory/spark.driver.memory— распределение памятиspark.sql.autoBroadcastJoinThreshold— порог для broadcast join
Интерактивная диаграмма: Что искать в Spark UI
Диаграмма выше показывает ключевые элементы каждой вкладки Spark UI и выделяет красные флаги — метрики, требующие вашего внимания. Кликайте по вкладкам Jobs, Stages и SQL, чтобы увидеть типичные проблемы и их индикаторы.
Чеклист диагностики
Когда Spark job медленный, проходите по этому чеклисту:
- Jobs tab — какой job самый долгий? Есть ли failed jobs?
- Stages tab — в каком stage bottleneck? Проверьте GC time и task distribution
- SQL tab — есть ли ненужные shuffle (Exchange)? Можно ли использовать broadcast?
- Storage tab — не переполнен ли кэш? Fraction Cached = 100%?
- Environment tab — правильные ли настройки AQE, памяти, partitions?
Как профилировать executor за пределами Spark UI — разбор на уровне исходников в senior-курсе:
Spark Internals: профилирование executorЧто дальше?
Spark UI показывает текущие и недавние приложения. Но что если вам нужно проанализировать job, который завершился вчера? Для этого существует History Server — инструмент для post-mortem анализа, который мы разберём в следующем уроке.