Как управлять средой PySpark-приложения в распределенной вычислительной среде: проблемы зависимостей Python в кластере и способы их решения с помощью сеансов Spark Connect в версии 3.5.0.
Управление зависимостями в Python и PySpark
Каждый Python-разработчик хотя бы раз сталкивался с проблемой несовместимости пакетов. Эта ситуация называется ад зависимостей (dependency hell), когда вновь установленные пакеты конфликтуют с теми, которые были ранее установлены из-за циклических зависимостей, несовпадения версий и т.д. Хотя есть инструменты, которые позволяют понять связи между зависимыми пакетами, например, Pydeps, Modulegraph, Pipdeptree, Snakefood, которые мы разбирали здесь. Эти библиотеки могут построить и визуализировать граф зависимостей, но не устраняют саму проблему dependency hell. В результате при разработке Python-приложения не получается использовать методы классов из этих пакетов. Например, у меня такое случается довольно часто, поскольку я обычно пишу и запускаю код в интерактивной среде Google Colab, которая имеет предустановленные Python-пакеты определенных версий. Впрочем, при конфликте зависимостей в Colab главным неприятным последствием будет неработающее приложение, а не полная переустановка системы.
Разумеется, профессиональные разработчики и дата-инженеры не пишут код в Colab, однако, тоже сталкиваются с адом зависимостей. Чтобы избежать этого, в экосистеме Python рекомендуется не просто устанавливать пакеты с помощью менеджера pip или conda, а использовать виртуальные среды, каждая из которых имеет собственный независимый набор Python-пакетов, установленных в их site-каталогах. Виртуальная среда создается поверх существующей базовой установки Python и может быть изолирована от нее. Для работы с виртуальными средами в Python есть модуль venv, который интегрирован с virtualenv – инструментом для создания изолированных Python-сред.
Виртуальная среда используется для хранения определенного интерпретатора Python, а также программных библиотек и двоичных файлов, необходимых для поддержки проекта, т.е. библиотеки или приложения. По умолчанию каждая виртуальная среда представляет собой «вещь в себе», т.е. она изолирована от других виртуальных сред, а также от интерпретаторов и библиотек Python, установленных в операционной системе. Код в виртуальной среде считается одноразовым, т.к. его легко удалить и воссоздать с нуля. При этом код приложения не считается переносимым или копируемым: для воспроизведения необходимо воссоздать ту же среду в новом месте. Благодаря изоляции виртуальной среды вероятность конфликта зависимостей существенно снижается.
В кластерной среде управление зависимостями становится еще сложнее, поскольку надо обеспечить наличие на всех узлах необходимой среды для выполнения кода и определить фактическое расположение точек сохранения пользовательского кода с помощью параметра __cpLocation. Поэтому Apache Spark предоставляет пользователям несколько способов управления зависимостями между узлами кластера с помощью параметров сценариев, таких как опции —jars, —packages и конфигурации в файлах spark.jars.*. Справедливости ради стоит отметить, мне лично не помогли опции —jars и –-packages запустить потоковое приложение Spark Structured Streaming в среде Colab, о чем я писала здесь. Однако, может быть, у вас получится). Возможно, подобной проблемы получится избежать, если использовать систему управления Python-пакетами Conda и «чистую» среду для запуска приложения Apache Spark.
Пользователи PySpark могут напрямую использовать среду conda для доставки своих сторонних пакетов Python, используя conda-pack — инструмент командной строки, создающий перемещаемые среды Conda. Он поддерживается во всех типах кластеров в Apache Spark, начиная с версии 3.1. В Apache Spark 3.0 и ранее его можно использовать только с YARN.
Как уже отмечено выше, помимо пакетных менеджеров pip и conda для создания изолированных сред Python можно использовать инструмент virtualenv. Начиная с Python 3.3, часть его функций была интегрирована в Python в качестве стандартной библиотеки в модуле venv. В Apache Spark начиная с версии 3.1 пользователи PySpark могут использовать virtualenv для управления зависимостями Python в своих кластерах, используя venv-pack аналогично conda-pack. Виртуальная среда может использоваться как в драйвере, так и в исполнителе. Инструмент venv-pack упаковывает текущую виртуальную среду в архивный файл, включая интерпретатор Python и зависимости. Однако, для его применения нужно, чтобы на всех узлах в кластере был установлен один и тот же интерпретатор Python, поскольку venv-pack упаковывает его в виде символической ссылки.
Создав архивный файл с виртуальной средой, можно напрямую передать или распаковать его, чтобы включить эту среду на исполнителях, используя опцию —archives или конфигурацию spark.archives, которая в YARN называется spark.yarn.dist.archives. Это также можно использовать для передачи в кластер с помощью spark-submit. Однако, при этом следует отключить настройку PYSPARK_DRIVER_PYTHON в режимах кластера Kubernetes или YARN.
Также при разработке и отладке PySpark-приложения можно использовать инструмент PEX для совместной доставки пакетов Python, который создает автономную среду Python. Это похоже на conda или virtualenv, но PEX-файл сам по себе является исполняемым и ведет себя аналогично обычному интерпретатору Python.
Однако PEX-файл не включает в себя интерпретатор Python, поэтому он должен быть установлен на всех узлах в кластере, при чем один и тот же. Чтобы перенести и использовать PEX-файл в кластере, его надо отправить его через конфигурацию spark.files или spark.yarn.dist.files в YARN. Также можно использовать опцию –files, поскольку PEX-файл не является каталогом или архивом. Аналогично работе с virtualenv, конфигурацию PYSPARK_DRIVER_PYTHON следует отключить для режимов кластера в YARN или Kubernetes. Подробнее про режимы развертывания Spark-приложения мы писали здесь.
Таким образом, управление зависимостями в Apache Spark имеет ограничения: зависимости добавляются только статически и не могут быть изменены во время выполнения. Разработчику необходимо устанавливать зависимости перед запуском драйвера. Чтобы решить эту проблему, в Apache Spark 3.5.0 введена поддержка управления зависимостями на основе сеансов. Эта новая функция позволяет динамически обновлять зависимости Python во время выполнения. Как именно это работает, рассмотрим далее.
Подход на основе сеансов в Spark Connect
Как отмечено выше, при запуске Spark-приложения в распределенной среде контекст Spark добавляет архив (пользовательскую среду), который позже автоматически распаковывается на узлах кластера, гарантируя наличие необходимых зависимостей для выполнения задания. Это упрощает управление зависимостями в кластерной среде, но ограничивает гибкость, позволяя установить зависимости статически только один раз перед запуском контекста и драйвера Spark.
Чтобы устранить это ограничение, в версии фреймворка 3.5.0 введена поддержка управления зависимостями на основе сеансов с помощью Spark Connect. Напомним, Spark Connect представляет собой клиент-серверную архитектуру, которая позволяет разделить клиентский и серверный компоненты, обеспечивая удаленное подключение к кластерам Spark через API DataFrame и неразрешенные логические планы в качестве протокола. За счет разделения клиента и сервера Spark, их можно использовать откуда угодно, включая различные IDE, а также интерактивные среды выполнения типа Google Colab и Jupyter Notebook. Впервые полноценная поддержка Spark Connect была выпущена в версии фреймворка 3.4.0, опубликованной в апреле 2023 года, что мы разбирали здесь.
Из-за клиент-серверной архитектуры Spark Connect управление Python-зависимостями становится еще сложнее, т.к. каждый клиент имеет свои собственные зависимости и среды. Поэтому в версии Spark 3.5.0 решено привязать управление зависимостями к сеансам. У каждого сеанса есть выделенный каталог, в котором хранятся все связанные файлы и архивы Python. Когда запускаются рабочие процессы Python, текущий рабочий каталог устанавливается в этот выделенный каталог. Это гарантирует, что каждый сеанс может получить доступ к своему конкретному набору зависимостей и сред, исключая потенциальные конфликты.
Таким образом, Spark Connect и подход на основе сеансов в версии фреймворка 3.5.0 позволяет динамически управлять зависимостями Python во время выполнения Spark-приложения с помощью ранее используемых инструментов: pip, conda, virtualenv и PEX.
Читайте в нашей новой статье, зачем Spark-приложение создает файл _SUCCESS, почему в нем нет данных, как его использовать, можно ли обойтись без него и как это сделать: пример запуска PySpark-приложения в Google Colab.
Код курса
SPAD
Ближайшая дата курса
Продолжительность
ак.часов
Стоимость обучения
0 руб.
Узнайте больше про возможности Apache Spark для разработки приложений аналитики больших данных на специализированных курсах в нашем лицензированном учебном центре обучения и повышения квалификации для разработчиков, менеджеров, архитекторов, инженеров, администраторов, Data Scientist’ов и аналитиков Big Data в Москве:
- Основы Apache Spark для разработчиков
- Потоковая обработка в Apache Spark
- Анализ данных с Apache Spark
- Машинное обучение в Apache Spark
- Графовые алгоритмы в Apache Spark
- Архитектура данных с Apache Spark
Источники