在 Spark 执行器节点上安装 Python 依赖项的最简单方法?
Easiest way to install Python dependencies on Spark executor nodes?
我知道您可以将单个文件作为 Python Spark 程序的依赖项发送。但是成熟的库(例如 numpy)呢?
Spark 是否有办法使用提供的包管理器(例如 pip)来安装库依赖项?还是必须在执行 Spark 程序之前手动完成?
如果答案是手动的,那么在大量分布式节点上同步库(安装路径、版本等)的"best practice"方法是什么?
实际上已经尝试过了,我认为我作为评论发布的 link 并没有完全按照您想要的依赖项进行操作。您非常合理地要求的是一种让 Spark 在安装依赖项方面与 setuptools 和 pip 很好地配合的方法。令我震惊的是,这在 Spark 中并没有得到更好的支持。第三方依赖问题在通用 Python 中已基本解决,但在 Spark 下,似乎假设您将返回到手动依赖管理或其他方式。
我一直在使用基于 virtualenv 的不完善但功能齐全的管道。基本思路是
- 为您的 Spark 节点创建一个虚拟环境
- 每次您 运行 一个 Spark 作业,运行 一个全新的
pip install
您自己的内部 Python 库。如果您已使用 setuptools
设置它们,这将安装它们的依赖项
- 压缩 virtualenv 的站点包目录。这将包括您的库及其依赖项,工作节点将需要这些库,但不包括他们已经拥有的标准 Python 库
- 将包含您的库及其依赖项的单个
.zip
文件作为参数传递给 --py-files
当然,您可能希望编写一些帮助脚本来管理此过程。这是一个改编自我一直在使用的帮助脚本,无疑可以改进很多:
#!/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=; shift
ZIPFILE=; 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
我有一组其他简单的包装脚本,我 运行 提交了我的 spark 作业。我简单地首先调用这个脚本作为该过程的一部分,并确保当我 运行 spark-submit
(作为记录在评论中)。我总是 运行 这些脚本,所以我永远不会意外地 运行 宁旧代码。与 Spark 开销相比,打包开销对于我的小规模项目来说是最小的。
有很多可以改进的地方——例如,聪明地决定何时创建一个新的 zip 文件,将其分成两个 zip 文件,一个包含经常变化的私有包,另一个包含很少变化的依赖项,这不需要那么频繁地重建。在重建 zip 之前,您可以更聪明地检查文件更改。检查参数的有效性也是一个好主意。但是现在这足以满足我的目的。
我提出的解决方案并不是专门为像 NumPy 这样的大型依赖项设计的(尽管它可能对它们有用)。此外,如果您正在构建基于 C 的扩展,并且您的驱动程序节点与您的集群节点具有不同的体系结构,它也将不起作用。
我在其他地方看到了关于 运行 像 Anaconda on all your nodes since it already includes NumPy (and many other packages 这样的 Python 发行版的建议,这可能是获得 NumPy 以及其他基于 C 的扩展的更好方法去。无论如何,我们不能总是期望 Anaconda 在正确的版本中拥有我们想要的 PyPI 包,此外你可能无法控制你的 Spark 环境来将 Anaconda 放在上面,所以我认为这个基于 virtualenv 的方法还是有帮助的。
我知道您可以将单个文件作为 Python Spark 程序的依赖项发送。但是成熟的库(例如 numpy)呢?
Spark 是否有办法使用提供的包管理器(例如 pip)来安装库依赖项?还是必须在执行 Spark 程序之前手动完成?
如果答案是手动的,那么在大量分布式节点上同步库(安装路径、版本等)的"best practice"方法是什么?
实际上已经尝试过了,我认为我作为评论发布的 link 并没有完全按照您想要的依赖项进行操作。您非常合理地要求的是一种让 Spark 在安装依赖项方面与 setuptools 和 pip 很好地配合的方法。令我震惊的是,这在 Spark 中并没有得到更好的支持。第三方依赖问题在通用 Python 中已基本解决,但在 Spark 下,似乎假设您将返回到手动依赖管理或其他方式。
我一直在使用基于 virtualenv 的不完善但功能齐全的管道。基本思路是
- 为您的 Spark 节点创建一个虚拟环境
- 每次您 运行 一个 Spark 作业,运行 一个全新的
pip install
您自己的内部 Python 库。如果您已使用setuptools
设置它们,这将安装它们的依赖项 - 压缩 virtualenv 的站点包目录。这将包括您的库及其依赖项,工作节点将需要这些库,但不包括他们已经拥有的标准 Python 库
- 将包含您的库及其依赖项的单个
.zip
文件作为参数传递给--py-files
当然,您可能希望编写一些帮助脚本来管理此过程。这是一个改编自我一直在使用的帮助脚本,无疑可以改进很多:
#!/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=; shift
ZIPFILE=; 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
我有一组其他简单的包装脚本,我 运行 提交了我的 spark 作业。我简单地首先调用这个脚本作为该过程的一部分,并确保当我 运行 spark-submit
(作为记录在评论中)。我总是 运行 这些脚本,所以我永远不会意外地 运行 宁旧代码。与 Spark 开销相比,打包开销对于我的小规模项目来说是最小的。
有很多可以改进的地方——例如,聪明地决定何时创建一个新的 zip 文件,将其分成两个 zip 文件,一个包含经常变化的私有包,另一个包含很少变化的依赖项,这不需要那么频繁地重建。在重建 zip 之前,您可以更聪明地检查文件更改。检查参数的有效性也是一个好主意。但是现在这足以满足我的目的。
我提出的解决方案并不是专门为像 NumPy 这样的大型依赖项设计的(尽管它可能对它们有用)。此外,如果您正在构建基于 C 的扩展,并且您的驱动程序节点与您的集群节点具有不同的体系结构,它也将不起作用。
我在其他地方看到了关于 运行 像 Anaconda on all your nodes since it already includes NumPy (and many other packages 这样的 Python 发行版的建议,这可能是获得 NumPy 以及其他基于 C 的扩展的更好方法去。无论如何,我们不能总是期望 Anaconda 在正确的版本中拥有我们想要的 PyPI 包,此外你可能无法控制你的 Spark 环境来将 Anaconda 放在上面,所以我认为这个基于 virtualenv 的方法还是有帮助的。