[英]I can't seem to get --py-files on Spark to work
我在 Spark 上使用 Python 时遇到问题。 我的应用程序有一些依赖项,例如 numpy、pandas、astropy 等。我不能使用 virtualenv 创建具有所有依赖项的环境,因为除了 HDFS 之外,集群上的节点没有任何公共挂载点或文件系统。 因此我坚持使用spark-submit --py-files
。 我将站点包的内容打包在一个 ZIP 文件中,并像使用--py-files=dependencies.zip
选项一样提交作业(如在 Spark 执行程序节点上安装 Python 依赖项的最简单方法中所建议的那样? )。 但是,集群上的节点似乎仍然没有看到内部的模块,并且在导入 numpy 时会抛出诸如此类的ImportError
。
File "/path/anonymized/module.py", line 6, in <module>
import numpy
File "/tmp/pip-build-4fjFLQ/numpy/numpy/__init__.py", line 180, in <module>
File "/tmp/pip-build-4fjFLQ/numpy/numpy/add_newdocs.py", line 13, in <module>
File "/tmp/pip-build-4fjFLQ/numpy/numpy/lib/__init__.py", line 8, in <module>
#
File "/tmp/pip-build-4fjFLQ/numpy/numpy/lib/type_check.py", line 11, in <module>
File "/tmp/pip-build-4fjFLQ/numpy/numpy/core/__init__.py", line 14, in <module>
ImportError: cannot import name multiarray
当我切换到 virtualenv 并使用本地 pyspark shell 时,一切正常,因此依赖项都在那里。 有谁知道,可能导致此问题的原因以及如何解决?
谢谢!
首先,我假设您的依赖项列在requirements.txt
。 要打包和压缩依赖项,请在命令行中运行以下命令:
pip install -t dependencies -r requirements.txt
cd dependencies
zip -r ../dependencies.zip .
上面, cd dependencies
命令对于确保模块位于 zip 文件的顶层至关重要。 感谢Dan Corin 的提醒。
接下来,通过以下方式提交作业:
spark-submit --py-files dependencies.zip spark_job.py
--py-files
指令将 zip 文件发送给 Spark 工作人员,但没有将其添加到PYTHONPATH
(让我感到困惑的根源)。 要将依赖项添加到PYTHONPATH
以修复ImportError
,请将以下行添加到 Spark 作业spark_job.py
:
sc.addPyFile("dependencies.zip")
任何使用商品硬件进行分布式计算的人都必须假设底层硬件可能是异构的。 由于需要 C 编译,因此在客户端机器上构建的 Python egg 将特定于客户端的 CPU 架构。 为 NumPy、SciPy 或 Pandas 等复杂的编译包分发鸡蛋是一种脆弱的解决方案,可能在大多数集群上失败,至少最终是这样。
虽然上面的解决方案没有构建一个鸡蛋,但同样的准则也适用。
首先,您需要通过--py-files或--files传递文件
现在在您的代码中,使用以下命令添加这些 zip/文件
sc.addPyFile("your zip/file")
现在使用如下别名在代码中导入您的 zip/文件以开始引用它
import zip/file as your-alias
注意:导入时不需要使用文件扩展名,如末尾的.py
希望这是有用的。
为了让这种依赖分布方法与编译扩展一起工作,我们需要做两件事:
使用以下脚本创建依赖项 zip 将确保您与系统上已安装的任何软件包隔离。 这是假设的virtualenv安装并requirements.txt
当前目录中存在,并输出dependencies.zip
与所有的依赖在根级别。
env_name=temp_env
# create the virtual env
virtualenv --python=$(which python3) --clear /tmp/${env_name}
# activate the virtual env
source /tmp/${env_name}/bin/activate
# download and install dependencies
pip install -r requirements.txt
# package the dependencies in dependencies.zip. the cd magic works around the fact that you can't specify a base dir to zip
(cd /tmp/${env_name}/lib/python*/site-packages/ && zip -r - *) > dependencies.zip
现在可以像这样部署、解压缩和包含在 PYTHONPATH 中的依赖项
spark-submit \
--master yarn \
--deploy-mode cluster \
--conf 'spark.yarn.dist.archives=dependencies.zip#deps' \
--conf 'spark.yarn.appMasterEnv.PYTHONPATH=deps' \
--conf 'spark.executorEnv.PYTHONPATH=deps' \
.
.
.
spark.yarn.dist.archives=dependencies.zip#deps
分发您的 zip 文件并将其解压缩到名为deps
的目录
spark.yarn.appMasterEnv.PYTHONPATH=deps
spark.executorEnv.PYTHONPATH=deps
在 PYTHONPATH 中为 master 和所有 worker 包含deps
目录
--deploy-mode 集群
在集群上运行主执行程序,以便它获取依赖项
您可以找到您需要的所有 .pys 并相对添加它们。 有关此说明,请参见此处:
import os, sys, inspect
# realpath() will make your script run, even if you symlink it :)
cmd_folder = os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe() ))[0]))
if cmd_folder not in sys.path:
sys.path.insert(0, cmd_folder)
# use this if you want to include modules from a subfolder
cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"subfolder")))
if cmd_subfolder not in sys.path:
sys.path.insert(0, cmd_subfolder)
# Info:
# cmd_folder = os.path.dirname(os.path.abspath(__file__)) # DO NOT USE __file__ !!!
# __file__ fails if script is called in different ways on Windows
# __file__ fails if someone does os.chdir() before
# sys.argv[0] also fails because it doesn't not always contains the path
Spark 也会默默地无法加载使用 python zipfile
模块创建的 zip 存档。 必须使用 zip 实用程序创建 Zip 存档。
尝试使用--archives
将您的 anaconda 目录存档到每个服务器,并使用--conf spark.yarn.appMasterEnv.PYSPARK_PYTHON=
告诉您的--conf spark.yarn.appMasterEnv.PYSPARK_PYTHON=
服务器您的 anaconda 目录中的 python 执行程序路径在哪里。
我们的完整配置是这样的:
--conf spark.yarn.appMasterEnv.PYSPARK_PYTHON=./ANACONDA/anaconda-dependencies/bin/python
--archives <S3-path>/anaconda-dependencies.zip#ANACONDA
正如 Andrej Palicka 在评论中解释的那样,
“问题在于,Python 无法从 .zip 文件(docs.python.org/2/library/zipimport.html)导入 .so 模块”。
我发现的一个解决方案是将非 .py 文件一一添加到由逗号分隔的 py 文件中:
spark-submit --py-files modules/toolbox.cpython-38-x86_64-linux-gnu.so,modules/product.cpython-38-x86_64-linux-gnu.so spark_fro
m_cython.py
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.