原文链接:https://blog.csdn.net/wangxiao7474/article/details/81391300
在spark上运行Python脚本遇到“ImportError: No module name xxxx”
这是因为运行Python脚本的集群上的Python环境里缺乏脚本运行需要的依赖。
根据所需依赖的不同性质可以分为3类:
(1)单个的*.py或者*.py[co]
(2)自建模块
(3)自包含的依赖项
(4)复杂依赖
【1】只依赖于单个文件(only depend on a sigle file)
(1)可以通过使用spark-submit命令中的—py-files选项并指定文件的本地路径,将依赖文件提供给所有的执行程序。
/opt/spark/bin/spark-submit --master yarn-cluster --py-files dependency.py my_script.py
(2)使用sc.addPyFiles(path)函数(文件路径作为参数)以编程的方式将所需文件添加到SparkContext。
sc = SparkContext(master=”yarn-cluster”,appName=”myApp”) sc.addPyFile(file_path)
【2】自建模块
比如在Python脚本中使用了
from model.file import *
那么就需要将model文件夹进行打包。注意打包指令要在文件所在的父目录下进行。比如文件夹model的路径为/home/workspace/model,那么就要保证打包命令是在/home/workspace/下进行的,但这样打包会将workspace文件夹下的文件全部打包。
zip -r ../my_dependencies.zip .
备注:这样操作的原因是,要确保所需文件在*.zip的顶层(ensure that the modules are the in the top level of the zip file),即当解压缩deps.zip时,文件和文件夹必须出现在顶层。当在spark中执行任务时,相关的依赖包会以如下方式进行查找:
/hadoopdir3/yarn/…/my_dependencies.zip/model/file/__init__.py
两种打包命令的区别:
正确的:
-
$ zip -r ../deps.zip .
-
adding: __init__.py (
stored
0%)
-
adding: _markerlib/ (
stored
0%)
-
adding: _markerlib/__init__.py (deflated
55%)
-
adding: _markerlib/__init__.pyc (deflated
60%)
-
adding: _markerlib/markers.py (deflated
63%)
-
adding: _markerlib/markers.pyc (deflated
61%)
-
adding: aniso8601/ (
stored
0%)
-
...
错误的:
-
$
zip -r deps.
zip folder_name
/*
-
adding: folder_name/__init__.py (stored 0%)
-
adding: folder_name/_markerlib/ (stored 0%)
-
adding: folder_name/_markerlib/__init__.py (deflated 55%)
-
adding: folder_name/_markerlib/__init__.pyc (deflated 60%)
-
adding: folder_name/_markerlib/markers.py (deflated 63%)
-
adding: folder_name/_markerlib/markers.pyc (deflated 61%)
-
adding: folder_name/aniso8601/ (stored 0%)
-
-
...
-
打包好之后,就可以按照【1】中分发单个文件给集群的方法将*.zip文件分发给集群。
/opt/spark/bin/spark-submit --master yarn-cluster --py-files my_dependency.zip my_script.py
或者
sc = SparkContext(master=”yarn-cluster”,appName=”myApp”) sc.addPyFile(file_path)
【3】自包含的依赖项(a self contained module (meaning a module with no other dependencies))
如果所需依赖是Python的第三方模块,可以通过virtualenv创建一个独立的Python运行环境,然后在这个Python运行环境里安装各种第三方包。然后将安装的第三方包打包成*.zip或者*.egg。
详细步骤如下:
第一步,用pip安装virtualenv
# Python2版本
pip2 install virtualenv
# Python3版本
pip3 install virtualenv
第二步,创建一个独立的Python运行环境,命名为pyspark-env
virtual –no-site-packages pyspark-env
# –no-site-packages,可以使已经安装的系统Python环境中的所有第三方包不会复制过来,这样可以得到一个不带任何第三方包的“干净的”的Python运行环境。
第三步,用source进入该环境
source pyspark-env/bin/activate
# 使用deactivate 命令退出当前env环境
deactivate
可以发现,命令提示符变了,有个pyspark-env前缀,表示当前环境使一个名为pyspark-env的Python环境。
第四步,正常安装各种第三方包
pip install numpy
在pyspark-env环境下,用pip安装的包都被安装到pyspark-env这个环境下,系统Python环境不受任何影响。
第五步,打包安装的第三方包
所有的第三方的包都会被pip安装到lib/python2/site-packages目录下面。
进入site-packages目录下面,
-
cd ./lib/python2.
7/site-packages
-
-
zip -r /
zip-path/my_dependencies.
zip
.同样也要注意,必须在所需包的父目录下进行打包,使文件和文件夹作为*.zip的顶层文件。
打包好之后,就可以通过
spark-submit –master yarn-cluster –py-files my_dependency.zip my_script.py
或者通过在脚本中sparkcontext的属性添加
sc.addfiles(“path/my_dependency.zip”)
将依赖库分发到各节点。
警告:如果您的软件包依赖于已编译的代码,并且您的集群中的计算机具有与您编译egg的代码不同的CPU体系结构,则这将不起作用。
比如Numpy,通过这种方式没有解决依赖的问题,最后是让集群管理员直接在集群上安装了Numpy。
主要原因是Python不允许动态导入.so文件,而Numpy由于是C编译的,存在*.so文件。
【4】复杂依赖(Complex Dependency)
要用的包依赖于其他的依赖项
比如Pandas依赖于NumPy和SciPy,以及其他包。
理论上,我们可以为所需的依赖包创建一个*.egg文件,然后通过命令行的—py-files选项,或者sc.addPyFiles()方法 将依赖文件传送给执行器。
但是对于复杂依赖,这种方法很脆弱:
A Python egg built on a client machine will be specific to the client’s CPU architecture because of the required C compilation. Distributing an egg for a complex, compiled package like NumPy, SciPy, or pandas is a brittle solution that is likely to fail on most clusters, at least eventually.
参考:
https://stackoverflow.com/questions/29495435/easiest-way-to-install-python-dependencies-on-spark-executor-nodes
https://stackoverflow.com/questions/35214231/importerror-no-module-named-numpy-on-spark-workers
https://www.cloudera.com/documentation/enterprise/5-5-x/topics/spark_python.html
https://blog.cloudera.com/blog/2015/09/how-to-prepare-your-apache-hadoop-cluster-for-pyspark-jobs/
https://stackoverflow.com/questions/36461054/i-cant-seem-to-get-py-files-on-spark-to-work
http://blog.danielcorin.com/code/2015/11/10/pyspark.html