spark
September 24, 2023

Как настраивать виртуальное окружение для работы со Spark

Интерактивная работа со Spark имеет свои особенности, главная из которых - всегда учитывать, что исполнение кода происходит на нескольких узлах. Одним из следствий этого является необходимость создания одинаковой виртуальной среды на нодах, так как иначе вы не можете гарантировать корректную работу. Это касается не только импортированных модулей, но и версии интерпретатора.

Готовим venv

Сначала найдем базовую версию Python, на основе которой сделаем venv. Если в вашем распоряжении Jupyter,выберите kernel с нужной версией Python и наберите команду:

import sys;sys.executable

Еще в вашем распоряжении терминал:

!which python3.7

Теперь создайте среду любым питоном так:

!python3.7 -m venv ../../envs/spark3.7_copy --copies

Благодаря параметру --copies в папке среды находятся интерпретаторы, а не ссылки на него:

Подводный камень заключается в том, что в зависимости от базового питона, с которым вы создаете среду, по умолчанию в ее bin директории вместо интерпретатора может быть создана ссылка на него (когда создается самим бинарником) либо вообще ссылка на ссылку (когда создается ссылкой). При передаче venv со ссылками на исполнители, вероятность, что по таким же путям будет нужный интерпретатор, кратно уменьшается, и вы рискуете получить ошибку. Поэтому при создании venv добавляйте параметр создания копий (например, для модуля venv - --copies) либо уже после вручную замените в bin директории ссылку на сам интерпретатор.

Для инфо, можно посмотреть на среды, которые создаются без параметра --copies разными путями:

По указанному выше пути (/usr/local/basement/Python-3.7.4/bin/) находится сам интерпретатор:

!ls -la /usr/local/basement/Python-3.7.4/bin/ | grep python

Создадим виртуальную среду:

!/usr/local/basement/Python-3.7.4/bin/python3.7 -m venv ../../envs/spark3.7

В результате в venv-е помещается ссылка на интерпретатор (у меня такой вариант создания среды сработал на уоркерах, видимо, из-за совпадения путей):

!ls -la ../../envs/spark3.7/bin | grep python

Когда же мы создаем venv через 'python3.7 -m venv' мы будем иметь дело со ссылкой на интерпретатор:

Без параметра --copies в нашу папку bin попадает link на link:

!python3.7 -m venv ../../envs/spark3.7_temp
!ls -la ../../envs/spark3.7_temp/bin | grep python

Как указывал выше, если в папке bin заменить ссылку на интерпретатор, то с условием выполнения последующих шагов все так же будет работать:

!rm ../../envs/spark3.7_temp/bin/python3.7 && cp /usr/local/basement/Python-3.7.4/bin/python3.7 ../../envs/spark3.7_temp/bin/

Упаковка среды

Следующим шагом идет упаковка среды. Сначала установите в среду пакет venv-pack:

!source ../../envs/spark3.7_copy/bin/activate && pip install venv-pack

Затем упакуйте ее с новым пакетом:

!source ../../envs/spark3.7_copy/bin/activate && venv-pack -o ../../envs/spark3.7_copy.tar.gz

Передача на исполнители

Передайте упакованную среду на уоркеры с конфигурационным параметром spark.archives или spark.yarn.dist.archives, если в качестве диспетчера ресурсов используется YARN:

spark.yarn.dist.archives=путь_к_архиву_с_venv#имя_папки

и установите переменную окружения PYSPARK_PYTHON:

os.environ['PYSPARK_PYTHON']='./имя_папки/bin/python'

Например, можно задать параметры так:

os.environ['PYSPARK_PYTHON']='./env/bin/python'

os.environ['PYSPARK_SUBMIT_ARGS'] = f''' ....
--conf spark.yarn.dist.archives=file:////home/.../envs/spark3.7_copy.tar.gz#env
'''

Проверка

Для проверки корректности создания окружения можете использовать такой код:

data = [{'name': 'Sasha'},\
{'name': 'Masha'}]

json_rdd = spark.sparkContext.parallelize(data)
sdf = spark.read.json(json_rdd)
sdf.show()

Если появится ошибка как ниже, значит, скорее всего, питон передан по ссылке:

Отмечу, что если важно с аналогичной средой работать в Jupyter на драйвере, можно создать kernel со ссылкой на нее, как описывал здесь.