Самый простой способ установить зависимости Python от узлов-исполнителей Spark?

Я понимаю, что вы можете отправлять отдельные файлы в зависимости от программ Python Spark. Но как насчет полноценных библиотек (например, numpy)?

Есть ли у Spark возможность использовать предоставленный менеджер пакетов (например, pip) для установки зависимостей библиотек? Или это нужно сделать вручную до запуска программ Spark?

Если ответ является ручным, то какие подходы к "лучшей практике" для синхронизации библиотек (путь установки, версия и т.д.) на большом количестве распределенных узлов?

Ответ 1

Фактически, фактически попробовав это, я думаю, что ссылка, которую я опубликовал как комментарий, не делает именно то, что вы хотите с зависимостями. То, что вы вполне разумно просите, - это способ, чтобы Spark отлично играли с setuptools и pip относительно установки зависимостей. Мне кажется, что в Спарке это лучше не поддерживается. Проблема зависимостей третьей стороны в значительной степени решена в Python общего назначения, но под Spark кажется предположением, что вы вернетесь к ручному управлению зависимостями или чему-то еще.

Я использовал несовершенный, но функциональный конвейер, основанный на virtualenv. Основная идея

  • Создайте virtualenv исключительно для ваших узлов Spark.
  • Каждый раз, когда вы запускаете задачу Spark, запустите новый pip install всех собственных собственных библиотек Python. Если вы установили их с помощью setuptools, это установит их зависимости
  • Заблокировать каталог-пакеты каталога virtualenv. Это будет включать в себя вашу библиотеку и ее зависимости, которые потребуются рабочим узлам, но не стандартная библиотека Python, которые у них уже есть.
  • Передайте одиночный .zip файл, содержащий ваши библиотеки и их зависимости, в качестве аргумента --py-files

Конечно, вы захотите закодировать некоторые вспомогательные скрипты для управления этим процессом. Вот помощник script, адаптированный из того, который я использовал, что, несомненно, может быть улучшено:

#!/usr/bin/env bash
# helper script to fulfil Spark python packaging requirements.
# Installs everything in a designated virtualenv, then zips up the virtualenv for using as an the value of
# supplied to --py-files argument of `pyspark` or `spark-submit`
# First argument should be the top-level virtualenv
# Second argument is the zipfile which will be created, and
#   which you can subsequently supply as the --py-files argument to 
#   spark-submit
# Subsequent arguments are all the private packages you wish to install
# If these are set up with setuptools, their dependencies will be installed

VENV=$1; shift
ZIPFILE=$1; shift
PACKAGES=$*

. $VENV/bin/activate
for pkg in $PACKAGES; do
  pip install --upgrade $pkg
done
TMPZIP="$TMPDIR/$RANDOM.zip" # abs path. Use random number to avoid clashes with other processes
( cd "$VENV/lib/python2.7/site-packages" && zip -q -r $TMPZIP . )
mv $TMPZIP $ZIPFILE

У меня есть коллекция других простых скриптов-оболочек, которые я запускаю, чтобы отправлять свои искровые задания. Я просто называю это script первым как часть этого процесса и удостоверяюсь, что второй аргумент (имя zip файла) затем передается как аргумент -py-files при запуске spark-submit (как описано в комментариях). Я всегда запускаю эти сценарии, поэтому я никогда не заканчиваю случайный запуск старого кода. По сравнению с издержками Spark накладные расходы на упаковку минимальны для моего небольшого проекта.

Есть много улучшений, которые могут быть сделаны - например, умение создавать новый zip файл, разделяя его на два zip файла, один из которых содержит часто меняющиеся частные пакеты, и один, содержащий редко изменяющиеся зависимости, t нужно перестраивать так часто. Вы могли бы умнее проверять изменения файлов перед перестройкой zip. Также правильная проверка правильности аргументов была бы хорошей идеей. Однако на данный момент это достаточно для моих целей.

Решение, которое я придумал, не предназначено для крупномасштабных зависимостей, таких как NumPy (хотя это может сработать для них). Кроме того, он не будет работать, если вы создаете расширения на основе C, а ваш драйвер node имеет другую архитектуру для узлов вашего кластера.

Я видел рекомендации в другом месте, чтобы просто запустить дистрибутив Python, например Anaconda на всех ваших узлах, поскольку он уже включает NumPy (и многие другие пакеты), и это может быть лучшим способом получить NumPy, а также другие расширения на основе C. Несмотря на это, мы не всегда можем ожидать, что Anaconda получит пакет PyPI, который мы хотим, в правильной версии, и, кроме того, вы не сможете контролировать свою среду Spark, чтобы иметь возможность установить Anaconda, поэтому я думаю, что этот виртуальный подход по-прежнему полезен.