Простое объяснение переноса промежуточных данных из памяти на диск в Spark, его влияния на скорость и способов понять причину.
Когда памяти недостаточно
Spark распределяет обработку данных между рабочими узлами. Во время сортировки или объединения одной задаче может понадобиться больше места для промежуточных результатов, чем доступно в её рабочей памяти. Тогда часть этих результатов временно записывается на диск. Такой перенос называют spill. Он помогает продолжить работу, но добавляет чтение и запись на более медленный носитель.
Представьте стол для сортировки папок. Пока стопки помещаются на столе, работать удобно. Когда места не хватает, часть папок приходится убирать на полку и потом снова доставать. Дело не обязательно в общем размере всей базы: важен объём, который нужен конкретной задаче в конкретный момент. Подробнее о том, чья именно память участвует в работе, есть статья о памяти рабочего узла и драйвера Spark.
Что уходит на диск
На диск может уйти промежуточное содержимое операции: например, данные, которые сортируют или собирают в группы перед следующим этапом. Это не то же самое, что плановая запись конечного результата в хранилище. И не всякая работа с диском означает проблему: система также читает входные файлы и может сохранять нужные ей данные по другим причинам.
В официальной документации Spark рабочая память и место для хранения повторно используемых данных описаны как разные потребности, которые делят общий ресурс. Документация отмечает, что отсутствие лишнего хранения в памяти способно уменьшить ненужный spill. Однако сам факт переноса ещё не говорит, какую настройку менять: сначала надо понять, на каком этапе и почему памяти не хватило.
Как это влияет на время
Запись промежуточных данных и их повторное чтение добавляют работу поверх основного вычисления. Если перенос невелик, пользователь может почти не заметить разницы. Если же большой объём многократно проходит через диск, этап обработки становится длиннее. Особенно заметно это при перекосе: одна часть набора данных оказывается значительно тяжелее остальных, и один рабочий процесс задерживает всю группу.
Похожее перераспределение данных между узлами называется shuffle, но это другое явление. Shuffle описывает перемещение и организацию данных для следующего этапа, а spill — ситуацию, когда промежуточной операции не хватило рабочей памяти. Они могут встречаться вместе. Разницу удобно понять в материале о shuffle в Spark.
Условный пример
Допустим, компания собирает продажи по магазинам. У большинства магазинов за день немного записей, но один крупный магазин даёт непропорционально много. Если обработка распределена неравномерно, задача для крупного магазина может потребовать намного больше рабочего места. Она начинает переносить промежуточные данные на диск, пока другие задачи уже завершились. Общий результат ждёт самого медленного участка.
Поспешное увеличение памяти для всех работников может оказаться дорогим и не решить перекос. Сначала сравнивают длительность отдельных задач, объём входных данных и распределение нагрузки. Возможно, нужен другой способ разделить работу; возможно, ограничение действительно связано с доступной памятью. Условный пример показывает, почему один показатель без контекста не даёт готового решения.
Что смотреть в метриках
Интерфейс наблюдения Spark показывает этапы и задачи, их время и показатели переноса данных. Сопоставьте этап с задержкой: все ли задачи стали медленнее или выделяются единицы? Затем проверьте объём переноса на диск и размер обрабатываемых частей. Показатель spill в памяти и объём записи на диск не обязаны совпадать: они характеризуют данные в разных представлениях.
Если рост времени совпал с увеличением объёма данных, причина может быть в масштабе задачи. Если изменилась только одна группа, ищите неравномерность. Если занята память хранения повторно используемых данных, оцените, нужна ли она именно здесь. Последовательное чтение метрик полезнее универсального совета «добавьте память». Практическую работу с распределённой обработкой можно изучить на курсе «PySpark для инженеров и аналитиков данных».


