¿La forma más fácil de instalar dependencias de Python en los nodos ejecutores Spark?

Entiendo que puede enviar archivos individuales como dependencias con los progtwigs de Python Spark. Pero ¿qué pasa con las bibliotecas completas (por ejemplo, numpy)?

¿Tiene Spark una forma de utilizar un administrador de paquetes proporcionado (por ejemplo, pip) para instalar dependencias de bibliotecas? ¿O esto tiene que hacerse manualmente antes de que se ejecuten los progtwigs Spark?

Si la respuesta es manual, ¿cuáles son los enfoques de “mejores prácticas” para sincronizar bibliotecas (ruta de instalación, versión, etc.) en una gran cantidad de nodos distribuidos?

En realidad, habiéndolo probado, creo que el enlace que publiqué como comentario no hace exactamente lo que quieres con las dependencias. Lo que razonablemente está pidiendo es una forma de que Spark juegue bien con setuptools y pip con respecto a la instalación de dependencias. Me hace pensar que esto no se admite mejor en Spark. El problema de dependencia de terceros se resuelve en gran medida en Python de uso general, pero bajo Spark, parece que la suposición es que volverás a la administración de dependencias manual o algo así.

He estado usando una tubería imperfecta pero funcional basada en virtualenv . La idea básica es

  1. Cree un virtualenv puramente para sus nodos Spark
  2. Cada vez que ejecuta un trabajo Spark, ejecute una nueva pip install de pip install de todas sus propias bibliotecas internas de Python. Si ha configurado esto con setuptools , esto instalará sus dependencias
  3. Comprima el directorio de paquetes de sitio de virtualenv. Esto incluirá su biblioteca y sus dependencias, que los nodos de trabajador necesitarán, pero no la biblioteca estándar de Python, que ya tienen.
  4. Pase el archivo .zip único, que contiene sus bibliotecas y sus dependencias como argumento para --py-files

Por supuesto, le conviene codificar algunos scripts de ayuda para gestionar este proceso. Aquí hay un guión de ayuda adaptado de uno que he estado usando, que sin duda podría mejorarse mucho:

 #!/usr/bin/env bash # helper script to fulfil Spark's 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 

Tengo una colección de otros scripts simples que ejecuto para enviar mis trabajos de chispa. Simplemente llamo a este script primero como parte de ese proceso y me aseguro de que el segundo argumento (nombre de un archivo comprimido) se pase como el argumento –py-files cuando ejecuto spark-submit (como se documenta en los comentarios). Siempre corro estos guiones, así que nunca termino accidentalmente ejecutando código viejo. En comparación con la sobrecarga de Spark, la sobrecarga del embalaje es mínima para mi proyecto de pequeña escala.

Hay muchas mejoras que se pueden hacer, por ejemplo, ser inteligente acerca de cuándo crear un nuevo archivo comprimido, dividirlo en dos archivos zip, uno que contenga paquetes privados que cambian a menudo, y uno que contenga dependencias que cambien con poca frecuencia, que no necesiten reconstruirse tan seguido Podría ser más inteligente al verificar cambios de archivos antes de reconstruir el zip. También sería una buena idea verificar la validez de los argumentos. Sin embargo, por ahora esto es suficiente para mis propósitos.

La solución que he propuesto no está diseñada específicamente para dependencias a gran escala como NumPy (aunque puede funcionar para ellas). Además, no funcionará si está creando extensiones basadas en C, y su nodo de controlador tiene una architecture diferente a sus nodos de clúster.

He visto recomendaciones en otros lugares para simplemente ejecutar una distribución de Python como Anaconda en todos tus nodos ya que ya incluye NumPy (y muchos otros paquetes ), y esa podría ser la mejor forma de hacer funcionar NumPy y otras extensiones basadas en C. A pesar de todo, no siempre podemos esperar que Anaconda tenga el paquete PyPI que queremos en la versión correcta, y además, es posible que no pueda controlar su entorno Spark para poder incluir Anaconda, así que creo que este virtualenv se basa en enfoque sigue siendo útil.