Первый сентябрьский день — время не только закупаться тетрадками и карандашами, но и отличная пора для обновления технологического стека. Тем более что не так давно вышел долгожданный Apache Spark 4.0 — первый мажорный релиз за последние несколько лет, который принёс столько изменений, что хватит на целый учебный год.
Вместо того, чтобы читать километры release notes, давайте сразу перейдём к самому важному: что нового появилось, что сломалось и как все эти изменения повлияют на данные и наши пайплайны.
Что требует внимания в первую очередь?
Сразу же рассмотрим изменения, которые ломают обратную совместимость. Их никак нельзя игнорировать при планировании перехода на Spark 4.0.
-
Scala 2.12 официально похоронен — теперь как минимум Scala 2.13. Это заставляет наконец-то мигрировать всех, кто застрял на старой версии.
-
Поддержка Java 8 и 11 также прекращена — обязательная версия теперь — это Java 17. Это огромнейший шаг, открывающий доступ к новым возможностям языка и лучшей производительности JVM. Здесь стоит отметить, что если кто-то до сих пор пользуется Spark с Java 8, то стоит постепенно обновить версию Java сначала до 11, а уже после до 17 (Spark с версии 3.5 её также уже поддерживает и этот шаг существенно упростит дальнейшую миграцию на Spark 4.0).
-
Включен строгий ANSI-режим по умолчанию — опция
spark.sql.ansi.enabled
теперь по умолчанию установлена в значениеtrue
. Таким образом, пайплайны, которые раньше молча прощали арифметические переполнения или неверные операции с датами, теперь будут падать с ошибками. Это значительное изменение в сторону корректности данных. Вернуть предыдущее поведение можно, установив значение опцииspark.sql.ansi.enabled
или переменнойSPARK_ANSI_SQL_MODE
вfalse
. -
Удалена поддержка Mesos — если кто-то всё ещё использует Mesos, то пора наконец-то задуматься о миграции на Kubernetes или YARN.
Подготовка к переходу на Spark 4.0 — это не просто обновление библиотек. Это полноценный проект по миграции с обновлением стека языков, рантаймов и, возможно, даже самого кластера.
Spark Connect — наше будущее
Spark Connect, который анонсировали в Spark 3.4, в версии 4.0 переживает взрывное развитие и практически становится центральной архитектурой для клиентских приложений.
-
Новый легковесный Python-клиент —
pyspark-client
весит всего 1.5 Мб против сотен мегабайт стандартного PySpark. -
Полная поддержка Java-клиента — теперь не только Python, но и Java-приложения смогут использовать тонкий клиент для подключения к удалённому Spark-кластеру.
-
ML на Spark Connect — появилась возможность тренировать ML-модели через удалённое соединение, что раньше было ограничено.
-
Swift-клиент — появление клиента для языка Swift — это довольно интересный шаг в сторону использования Spark в мобильной разработке.
Архитектура Spark окончательно разделяется на производительный, но тяжёлый движок на кластере и легковесные клиенты для доступа к нему. Это существенно меняет принципы разработки и деплоя приложений.
Spark SQL — мощь и выразительность
- Тип данных VARIANT (возможно, главная фича всего релиза для SQL) — предназначен для
обработки полуструктурированных данных, например, JSON, позволяя хранить иерархические структуры
данных в одном столбце и эффективно работать с ними. Также поддерживает работу с данными без
предварительного определения схемы.
Однако в настоящее время у него есть некоторые ограничения:- не все операции поддерживаются, например, выбор значений по ключу пока в разработке
- такое поле не может быть использовано для группировки, сортировки или выступать в качестве ключа для партиционирования
- также не будет работать операция
distict
-
SQL User-Defined Functions (UDFs) — теперь можно создавать пользовательские функции прямо на SQL, без погружения в Scala или Python. Это будет огромный плюс для наших аналитиков.
CREATE FUNCTION square(x INT) RETURNS INT RETURN x * x; SELECT square(5); -- 25
В техническом плане такие функции просто подставляются в конечный запрос по месту использования в виде подготовленного шаблона. И пока что нет возможности использовать циклы или условия, но это уже большой шаг вперёд.
-
Session Variables — аналог переменных в традиционных СУБД. Крайне полезно для передачи параметров между несколькими запросами в рамках одной сессии.
-- Устанавливаем переменные сессии в начале скрипта или ноутбука SET report_date = '2025-09-01'; SET country = 'Russia'; -- Используем их в первом запросе SELECT COUNT(*) AS total_orders FROM orders WHERE date = ${report_date} AND country = ${country}; -- Используем те же переменные во втором запросе SELECT SUM(revenue) AS total_revenue FROM sales WHERE date = ${report_date} AND country = ${country}; -- И в третьем, четвертом, пятом... -- Чтобы изменить дату и страну для всего отчета, -- нужно поменять значения всего в двух командах SET.
Кроме того в переменную можно записать и результат подзапроса:
-- Устанавливаем порог (количество сигм) SET sigma_threshold = 2.0; -- Считаем среднее и стандартное отклонение SET avg_revenue = (SELECT AVG(revenue) FROM sales); SET stddev_revenue = (SELECT STDDEV(revenue) FROM sales); -- Рассчитываем границу и используем сразу несколько переменных SET revenue_threshold = ${avg_revenue} + (${sigma_threshold} * ${stddev_revenue}); -- Фильтруем выбросы по рассчитанному порогу SELECT * FROM sales WHERE revenue > ${revenue_threshold};
-
Поддержка колляций (String Collation) — теперь правильная сортировка строк с учетом кодировки, языка и регистра наконец-то встроена в движок. Также если правильно указать кодировку, можно существенно увеличить производительность при сравнении и фильтрации строк.
-
Встроенная поддержка XML — добавлена к стандартным JSON, CSV, Avro. Парсинг XML с использованием новых функций
from_xml
,schema_of_xml
иxpath
становится тривиальной задачей. -
Pipe-синтаксис — теперь можно организовать цепочки преобразований в SQL в более удобном, а главное более читабельном, последовательном стиле.
Вместо, например, такого стандартного запроса:
SELECT c_count, COUNT(*) AS custdist FROM (SELECT c_custkey, COUNT(o_orderkey) c_count FROM customer LEFT OUTER JOIN orders ON c_custkey = o_custkey AND o_comment NOT LIKE '%unusual%packages%' GROUP BY c_custkey) AS c_orders GROUP BY c_count ORDER BY custdist DESC, c_count DESC;
Можно писать следующим образом:
FROM customer |> LEFT OUTER JOIN orders ON c_custkey = o_custkey AND o_comment NOT LIKE '%unusual%packages%' |> AGGREGATE COUNT(o_orderkey) c_count GROUP BY c_custkey |> AGGREGATE COUNT(*) AS custdist GROUP BY c_count |> ORDER BY custdist DESC, c_count DESC;
Подробнее о синтаксисе можно узнать на странице исследования в Google Research.
Spark SQL и DataFrame/Dataset API получили огромное количество новых функций, которые закрывают давние боли и открывают множество новых сценариев, что продолжает превращать Spark SQL в полнофункциональную распределённую СУБД.
PySpark растёт и развивается
-
Python Data Source API V2 — это переписанный и более эффективный API для написания коннекторов к данным (в том числе и собственных) на чистом Python.
-
User-Defined Table Functions (UDTFs) — мощнейшая возможность для пользовательских функций, позволяющая возвращать из Python-функций целые таблицы, а не отдельные значения или строки. Наконец-то это работает не только для Scala или Java.
-
Plotting API — добавлен нативный API для построения графиков прямо из Spark DataFrame, без необходимости вытягивания данных в Pandas и использования дополнительных библиотек. В результате легковесный Python-клиент для Spark Connect теперь может не только выполнять запросы, но и строить графики, что открывает широкие возможности для удалённой аналитики.
PySpark вышел на новый уровень зрелости, предлагая уникальные фичи (вроде UDTF) и решая давние проблемы разработчиков.
Structured Streaming
-
Arbitrary State API v2 — новая, более гибкая версия API для работы с состоянием в стриминге. Она даёт гораздо больший контроль и лучшую производительность. Одна из тех фич Spark, для которой стоит потратить время на написание отдельной статьи.
-
State Data Source — пожалуй, главнейшая фича релиза для стриминга! Позволяет нам запросить состояние стримингового приложения напрямую, как из обычной таблицы. Это решает огромную проблему отладки и мониторинга состояния. И это также достойно своей статьи в блоге.
-
Python Streaming Data Sources — теперь создание собственных источников для чтения потоковых данных на Python стало реальностью.
В новой версии Spark делает огромный шаг к тому, чтобы сделать стриминг таким же прозрачным и удобным для отладки, как и работу с обычными данными.
Мониторинг и управление
-
Structured Logging — логи перестают быть просто текстом, а становятся структурированными данными, которые не только проще парсить, но и возможно легко обрабатывать, агрегировать и анализировать в том числе и самим Spark’ом.
-
Spark Kubernetes Operator — реализован отдельный оператор, который упрощает управление жизненным циклом Spark-приложений в K8s.
-
Улучшенный Spark UI
- флейм-графы для дампов потоков
- обновлённая отрисовка для DAG’ов
- метрики для Python UDF
- и другие мелочи…
Итоги
Apache Spark 4.0 — это не просто обновление. Это полноценная смена эпохи в обработке данных с помощью Spark. Как сам Spark и его библиотеки получили множество изменений, нововведений и улучшений, так и вся его экосистема и зависимости были обновлены до актуальных версий, а всё устаревшее отрезано и забыто.
Релиз получился насыщенным, сложным и с большим заделом на будущее. Что же по поводу рекомендаций:
-
Для новых проектов — смело начинайте с Spark 4.0.0, учитывая требования к Java 17 и Scala. Это позволит уже сейчас получить массу новых возможностей и буст по производительности.
-
Для существующих проектов — планируйте миграцию как большой и сложный проект. Если у вас версия Spark ниже 3.5, то начните с обновления до неё, после чего стоит обновить Java и Scala. Затем протестируйте все пайплайны с включенной опцией
spark.sql.ansi.enabled=true
. И только после решения всех возникших при этом проблем обновляйте сам Spark до версии 4.
Apache Spark 4.0 — это наше будущее, которое наступает уже сегодня.