Получи случайную криптовалюту за регистрацию!

Apache Spark нынче практически индустриальный стандарт для раб | Anscombe's Quartet

Apache Spark нынче практически индустриальный стандарт для работы с данными. Как и любой долго развивающийся IT проект с длинной историей, он имеет довольно сложную архитектуру, а некоторые интерфейсы местами сделаны достаточно сложно (а некоторые - наоборот, исключительно гибко и удобно). К сожалению, без более-менее общего понимания того, как работает этот фреймворк, невозможно писать на нем качественные и сложные приложения - зачастую люди натыкаются на базовые ошибки или неверно используют API.

Вот характерный пример, который не так давно встретился в моей практике. У одной из смежных команд стояла задача организовать регулярное чтение данных из S3 path с большим количеством мелких JSON файлов, а затем сохранить результат в обычный parquet format. Первая версия написанной джобы была достаточно тривиальной:


spark.read
.schema(someSchema)
.format("json")
.load(s3path)
.write
.format("parquet")
.partitionBy("date")
.save(anotherS3Path)


Несмотря на кажущуюся простоту задачи, джоба выполнялась в среднем около 9 часов. Первое обвинение, как и положено, полетело в сторону фреймворка - какой же медленный этот ваш Apache Spark!
Догадливый читатель почти наверняка понял, в чем же была проблема - количество файлов.
По умолчанию, спарк будет генерировать по одной партиции на каждый JSON-файл. Это не проблема когда JSON-файлы большие и внутри них много записей, но в приведенном случае общее количество файлов было более 50k и прирастало с течением времени.

Оптимизация в данном случае тривиальна:


spark.read
.schema(someSchema)
.format("json")
.load(s3path)
.coalesce(spark.sparkContext.defaultParallelism)
.write
.format("parquet")
.partitionBy("date")
.save(anotherS3Path)


Coalesce изменяет план вычислений, собирая в кучу разрозненные мелкие файлы, в результате чего создается меньшее количество тасков с большим количеством данных внутри, что позволяет обходить затраты на создание/закрытие отдельных тасков под каждый файл. Результат -одна строчка изменила скорость выполнения этой джобы с 9 часов до 1 часа.

Это я все к чему - для хорошего Data Engineer понимание того, что происходит под капотом Spark является одной из важнейших доменных областей. Вот хорошая дока от одного из коммитеров спарка - она подробно обьясняет все шаги, которые происходят при запуске Spark-приложений:

https://github.com/JerryLead/SparkInternals