Опишите workflow отладки решения на Spark и типичные проблемы с их решением
Что проверяют
Работали ли вы со Spark на кластере, а не только в ноутбуке на маленьком файле. Отладка здесь устроена иначе, чем в обычном приложении: код исполняется на исполнителях, брейкпойнт туда не поставить, а ошибка всплывает не там, где написана, потому что преобразования ленивые.
Как отвечать
Опишите порядок, которым идёте:
- воспроизвести на выборке локально, чтобы отделить ошибку логики от проблемы масштаба;
- посмотреть план через
df.explain("formatted"): доехали ли фильтры до источника, обрезались ли лишние партиции; - открыть Spark UI, найти долгий этап и сравнить медианное время задачи с максимальным, разрыв означает перекос данных;
- посмотреть объём перемешивания, сброс на диск и долю времени на сборке мусора;
- читать логи исполнителя, а не только стек драйвера.
Типичные проблемы называйте вместе с причиной. Перекос ключей: одна задача тянет большую часть строк, лечится солью в ключе, широковещательным соединением для маленькой таблицы, адаптивным выполнением, которое умеет дробить перекошенные партиции. Нехватка памяти чаще идёт не от малого лимита, а от collect() на большом наборе или от того же перекоса. Медленные пользовательские функции на Python: данные гоняются в отдельный процесс, выручают встроенные функции или векторизованные UDF поверх Arrow. Отдельно мелкие файлы: тысячи задач по несколько килобайт.
Где спотыкаются
Рассказывают про пошаговую отладку и печать внутри преобразования. На кластере этот вывод уходит в лог исполнителя, а не на экран, и на больших данных не даёт ничего.
Второе: на любую нехватку памяти отвечают «поднять лимит исполнителю». Иногда помогает, но чаще просто откладывает падение: перекос памятью не лечится.
Третье: лечат всё кэшированием. cache() занимает ту самую память, которой не хватает, кэш без освобождения живёт до конца приложения, а данные, прочитанные однажды, кэшировать незачем.