Ответ
Когда Spark-приложение падает, я действую по чек-листу, начиная с самых частых причин.
1. Анализ логов драйвера (Driver Logs).
Первым делом смотрю логи контейнера драйвера (в YARN, K8s или на выделенном сервере). Ищу Exception или Error в конце лога. Частая ошибка — java.lang.OutOfMemoryError: Java heap space.
2. Использование Spark History Server UI. Если приложение упало, его логи доступны в History Server. Я проверяю:
- Вкладка «Executors»: Были ли исключения на исполнителях (Executor Lost).
- Вкладка «Stages»: На каком этапе (Stage) произошел сбой. Если задачи (Tasks) постоянно терпят неудачу (Failed) на одном этапе — проблема в данных или логике этого этапа.
3. Проверка конфигурации памяти. Падение часто связано с нехваткой памяти. Я проверяю и при необходимости увеличиваю ключевые параметры, учитывая накладные расходы:
# Пример настройки для spark-submit
spark-submit
--executor-memory 8g
--driver-memory 4g
--conf spark.executor.memoryOverhead=2g # Важно для off-heap памяти
--conf spark.driver.maxResultSize=2g
my_app.py
4. Отладка проблем с данными. Если падение происходит при чтении данных, я добавляю отладочную печать схемы и проверку на «битые» записи:
val df = spark.read.parquet("hdfs://path/to/data")
println("Schema:")
df.printSchema()
// Чтение с режимом PERMISSIVE для отлова corrupt-записей
val dfSafe = spark.read
.option("mode", "PERMISSIVE")
.option("columnNameOfCorruptRecord", "_corrupt_record")
.parquet("hdfs://path/to/data")
// Поиск записей, которые не удалось распарсить
dfSafe.filter($"_corrupt_record".isNotNull).show(false)
5. Логирование внутри кода. В сложных случаях я добавляю стратегическое логирование до и после трансформаций, чтобы локализовать проблемный участок кода.