我似乎无法在Spark上使用--py文件来工作

时间:2016-04-06 19:51:13

标签: python apache-spark pyspark

我在Spark上使用Python时遇到了问题。我的应用程序有一些依赖项,例如numpy,pandas,astropy等。我不能使用virtualenv来创建一个包含所有依赖项的环境,因为除了HDFS之外,集群上的节点没有任何公共mountpoint或文件系统。因此,我坚持使用spark-submit --py-files。我将站点包的内容打包到ZIP文件中,并像--py-files=dependencies.zip选项一样提交作业(如Easiest way to install Python dependencies on Spark executor nodes?中所述)。但是,群集上的节点似乎仍然没有看到内部的模块,并且在导入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时,一切正常,所以依赖关系都在那里。有谁知道,什么可能导致这个问题以及如何解决它?

谢谢!

6 个答案:

答案 0 :(得分:42)

首先,我假设您的依赖项列在requirements.txt中。要打包和压缩依赖项,请在命令行运行以下命令:

pip install -t dependencies -r requirements.txt
cd dependencies
zip -r ../dependencies.zip .

上面,cd dependencies命令对于确保模块位于zip文件的顶层是至关重要的。感谢Dan Corin's post提醒。

接下来,通过以下方式提交作业:

spark-submit --py-files dependencies.zip spark_job.py

--py-files指令将zip文件发送给Spark工作人员,但不将其添加到PYTHONPATH(对我来说是混乱的来源)。要将依赖项添加到PYTHONPATH以修复ImportError,请将以下行添加到Spark作业spark_job.py

sc.addPyFile("dependencies.zip")

来自this Cloudera post的警告:

  

假设任何人使用商品进行分布式计算   硬件必须假设底层硬件是潜在的   异质。在客户端计算机上构建的Python egg将是特定的   因为所需的C而导致客户端的CPU架构   汇编。为一个复杂的编译包分发一个鸡蛋   NumPy,SciPy或pandas是一个可能会失败的脆弱解决方案   大多数集群,至少最终。

虽然上述解决方案不会产生鸡蛋,但适用相同的指南。

答案 1 :(得分:10)

  • 首先,您需要通过 - py-files - 文件

    传递您的文件
    • 当您使用上述标记传递zip /文件时,基本上您的资源将被转移到HDFS上创建的临时目录,仅用于该应用程序的生命周期。
  • 现在,在您的代码中,使用以下命令添加这些zip /文件

    sc.addPyFile("your zip/file")

    • 上面的内容是,它将文件加载到执行环境,如JVM。
  • 现在使用以下别名导入您的代码中的zip /文件以开始引用它

    import zip/file as your-alias

    注意:导入时无需使用文件扩展名,例如 .py

希望这很有用。

答案 2 :(得分:4)

要使这种依赖分发方法与已编译的扩展配合使用,我们需要做两件事:

  1. 在与目标群集相同的操作系统上运行pip安装(最好在群集的主节点上)。这样可确保兼容的二进制文件包含在您的zip中。
  2. 在目标节点上解压缩存档。这是必需的,因为Python不会从zip文件导入已编译的扩展名。 (https://docs.python.org/3.8/library/zipimport.html

使用以下脚本创建依赖项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中将deps目录包含在master和所有worker的

-部署模式群集
在群集上运行主执行程序,以便它拾取依赖项

答案 3 :(得分:0)

您可以找到所需的所有.pys并相对添加。 有关此解释,请参阅here

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

答案 4 :(得分:0)

Spark也会无法加载使用python zipfile模块创建的zip存档。必须使用zip实用程序创建Zip存档。

答案 5 :(得分:0)

尝试使用--archives将anaconda目录存档到每个服务器  并使用--conf spark.yarn.appMasterEnv.PYSPARK_PYTHON=告诉您的spark服务器在anaconda目录中的python executor路径在哪里。

我们的完整配置是这样的:

--conf spark.yarn.appMasterEnv.PYSPARK_PYTHON=./ANACONDA/anaconda-dependencies/bin/python 

--archives <S3-path>/anaconda-dependencies.zip#ANACONDA