Я выполняю задание Spark на AWS Glue. Задание преобразует данные и сохраняет вывод в паркетные файлы, разбитые по дате (каталоги года, месяца, дня). Задание должно иметь возможность обрабатывать терабайты входных данных и использовать сотни исполнителей, каждый с ограничением памяти 5,5 ГБ.
Входные данные охватывают данные за более чем 2 года. Выходные паркетные файлы для каждой даты должны быть как можно больше, при желании разбитые на блоки по 500 МБ. Создание нескольких небольших файлов для каждого дня не требуется.
Мало проверенных подходов:
- повторное разбиение по тем же столбцам, что и при записи, приводит к ошибкам Out Of Memory для исполнителей:
df = df.repartition(*output_partitions)
(df
.write
.partitionBy(output_partitions)
.parquet(output_path))
- повторное разбиение с дополнительным столбцом со случайным значением приводит к записи нескольких небольших выходных файлов (соответствует значению
spark.sql.shuffle.partitions
):
df = df.repartition(*output_partitions, "random")
(df
.write
.partitionBy(output_partitions)
.parquet(output_path))
- установка количества разделов в функции
repartition
, например, на 10, дает 10 довольно больших выходных файлов, но я боюсь, что это вызовет ошибки Out Of Memory, когда будут загружены фактические данные (размером с ТБ):
df = df.repartition(10, *output_partitions, "random")
(df
.write
.partitionBy(output_partitions)
.parquet(output_path))
(df
в фрагментах кода - это обычный фрейм данных Spark)
Я знаю, что могу ограничить размер выходного файла с помощью опции записи maxRecordsPerFile
. Но это ограничивает вывод, создаваемый из одного раздела памяти, поэтому, в первую очередь, мне нужно создать разделы по дате.
Итак, вопрос: как переразбить данные в памяти на:
- разделить его между несколькими исполнителями, чтобы предотвратить ошибки Out Of Memory,
- сохранить вывод за каждый день в ограниченное количество больших паркетных файлов ,
- записывать выходные файлы параллельно (используя как можно больше исполнителей)?
Я читал эти источники, но не нашел решение: