pyspark程序运行报错:no module named XXX(本地pycharm没问题而线上cmd下运行有此问题)

(一)场景问题

1)我在本地pycharm项目分支下运行文件,运行方式是:先cd到项目根目录,然后再运行本地提交命令;现在把该部分代码打包上传到线上,直接在命令行运行,就会报no module named XXX错误;
本地目录:

  • gd_data
    • biz
      • t14
        • sub
          • clean_data
            • data_clean
              • clean_saic_part1.py(含import clean_utils_gz as cl)
              • clean_utils_gz.py
                备注: gd_data目录下含有__init__.py;
                复制到线上之后,类似的方式运行,会报错:no module named XXX

解决思路1

因为考虑到之前,spark-submit提交的时候,运行的py文件是直接在根目录下,并没有像这样嵌套在多级子目录里面;因此考虑的解决方式是:在根目录下面建一个调度文件,类似于main.py文件一样;看能否解决问题,但其实发现不能解决;但这种思路能解决另一种导入问题(见后续讨论-2019-3-20的Python包导入问题);调试了一天,将clean_utils_gz.py移到根目录下,或者将运行的py文件里面import clean_utils_gz as cl改成from biz.t14.sub.clean_data.data_clean import clean_utils_gz as cl;还有尝试将文件打包成zip包,添加进–py-files参数;还有尝试添加进sc.addfiles()里面,都没有解决,直到下方思路2才解决;

解决思路2
用以下提交方式完美运行:

spark-submit --master spark://192.168.31.10:7077 --executor-memory 120G --total-executor-cores 40  --py-files  /data3/test/gd_data_code/clean_utils_gz.py  /data3/test/gd_data_code/biz/t14/sub/clean_data/data_clean/clean_saic_part9_com_releated.py

注意两点:

  • (1)参数–py-files:只要保证添加的依赖py文件路径是存在的即可,能添加成功即可,依赖文件放在哪不重要,经验证,依赖文件并不需要放在子目录运行文件同级下,即与clean_saic_part9_com_releated.py同级,(ps:虽然,该运行文件里面可以这样写import clean_utils_gz as cl;我想大概是由于pyspark运行的时候,本身会把该文件实现与运行文件同级,因此,运行文件可以直接调用);
  • (2)运行文件:只需要是多级子目录下那个最终的运行文件clean_saic_part9_com_releated.py即可;不需要是在根目录下创建调用clean_saic_part9_com_releated.py的t14_main_update.py这个main文件;经验证,如果运行文件是main文件;即像下面这样提交:
     spark-submit --master spark://192.168.31.10:7077 --executor-memory 120G --total-executor-cores 40  --py-files  /data3/test/gd_data_code/clean_utils_gz.py  /data3/test/gd_data_code/t14_main_update.py

还是会报导入包错误:

ImportError: ('No module named biz.t14.sub.clean_data.data_clean.clean_utils_gz', , ('biz.t14.sub.clean_data.data_clean.clean_utils_gz',))

思路2解决的具体原因有待再详究
(2)pyspark里面spark-submit提交任务各种包依赖的情况
在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
###备注;文件和文件夹必须出现在顶层的含义:/my_dependencies.zip/解压后即为根目录my_dependencies;model路径就在.../my_dependencies/model下;

两种打包命令的区别:
正确的:

$ 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

知识补充这部分转载自:https://blog.csdn.net/wangxiao7474/article/details/81391300

你可能感兴趣的:(spark海量数据分析)