在使用pyspark运行python代码的过程中,通常遇到集群环境中没有相应的python三方库,即:ImportError: No module named ** ,对于该种情况,通常有两种解决方案:
1. 集群中的python环境安装相应的三方库! 走流程、找运维,贼麻烦
2. 集群未配置python环境,加载虚拟python环境!(重点讲解该方式,用起来贼方便)
使用pyspark过程中,遇到没有相应python库,可以通常有三种处理方法:
1.单一py文件
spark-submit命令中添加 --py-files a.py 即可:
spark-submit \
--master yarn \
--deploy-mode cluster \
--num-executors 40 \
--queue default \
--verbose \
--py-files a.py \
b.py
2.自建模块或python简单三方库(不含.so文件, 如 jieba)
直接将python相应的模块如(jieba包)打包为zip,然后spark-submit命令中动态加载该模块即可;(本人直接将windows下python环境中site-packages 中的jieba 打包为zip, 然后使用如下提交命令就可以直接使用,注意模块的依赖包)
注意点:
1.模块存在依赖包
2.zip 包文件较大可以先将zip包上传到HDFS中
3.当有多个模块需要引用时,可以使用逗号分隔
spark-submit \
--master yarn \
--deploy-mode cluster \
--num-executors 40 \
--queue default \
--verbose \
--py-files hdfs://xxx/jieba.zip \
b.py
3.python复杂三方库(含.so 文件,即动态加载库,如numpy、pandas)(本文重点讲解该方法)
1.在任意台机器上安装Anaconda 软件
2.通过Anaconda 创建虚拟Python环境
(尝试过使用virtualenvwrapper 创建虚拟环境,但是在应用时失败了,建议直接使用Anaconda,具体原因见文末)
3.在创建好的Python环境中安装依赖的Python包
4.将整个虚拟Python环境打包为zip,或tar.gz包
进入到虚拟环境下,如/home/hadoop/anaconda3/envs,使用以下命令将虚拟环境进行打包
zip -r conda_env.zip conda_env # 虚拟环境为conda_env, 打包为conda_env.zip 文件
5.提交Pyspark Application,通过 --archives 选项指定 zip 包路径(可以将虚拟环境zip上传到HDFS或某个节点下 ),然后是在cluster、client模式下提交application,示例如下
spark-submit 提交application时主要是添加如下三行conf,对于cluster与client存在差异
--conf spark.yarn.dist.archives=/wang/code/conda_env \
--conf spark.pyspark.driver.python=/wang/code/conda_env/bin/python \
--conf spark.pyspark.python=/wang/code/conda_env/bin/python \
######################## cluster模式
spark-submit \
--master yarn \
--deploy-mode cluster \
--num-executors 50 \
--queue default \
--verbose \
--conf spark.yarn.dist.archives=hdfs:wang/conda_env.zip#python36 \
--conf spark.pyspark.driver.python=./python36/conda_env/bin/python \
--conf spark.pyspark.python=./python36/conda_env/bin/python \
test.py
注意:
1、hdfs:/// 是三条斜杠,之前参考其他资料写的两条斜杠一直报错
2、archives 命令后的 # 是必须的(通常会以为是注释),它指的是将 zip包 临时解压到的文件夹,后续两条--conf命令直接引用该文件夹即可
3、在提交 Pyspark Application 时会将该环境 zip 包上传到运行Application 的所在的每个节点上,并解压缩为Python 代码提供运行环境,如果不想每次都从客户端将该环境文件上传到集群中运行 pyspark application 的节点上,可以采用zip 包上传到HDFS的方式即可
######################## client模式
spark-submit \
--master yarn \
--deploy-mode client \
--driver-memory 2g \
--num-executors 50 \
--queue default \
--verbose \
--conf spark.yarn.dist.archives=hdfs:wang/conda_env.zip#python36 \
--conf spark.pyspark.driver.python=/mnt/wang/conda_env/bin/python \
--conf spark.pyspark.python=./python36/conda_env/bin/python \
test.py
注意:
1、与cluster主要不同在 --conf spark.pyspark.driver.python
对应的路径为提交application 的节点上解压conda_env.zip 后对应的/bin/python路径,即conda_env.zip 解压后的路径为/mnt/wang/conda_env/ ,然后再加上对应的路径下的 /bin/python,其目的就是集群 driver节点使用的python环境
补充:为什么使用virtualenv创建的虚拟环境无法作为python环境应用到Pyspark任务中??
归其主要原因还是在于:virtualenv本质上并不能真正隔离系统的python环境和自身虚拟环境的python环境,即使用virtualenv创建的虚拟环境与系统的python环境仍然存在关联,具体可以在virtualenv创建的虚拟环境中测试以下代码
import sys, json, _json
print(sys.path)
print(json.__file__)
print(_json.__name__)
在这个例子中,我们创建了一个虚拟环境 t2 ,并尝试在虚拟环境 import Python 自带的 json 模块,结果发现引用的模块地址事实上是操作系统而不是虚拟环境的。
从 sys.path 的结果可以看到,虚拟环境中的 Python import 模块时会尝试先从虚拟环境中的 Python PATH 搜索,然后会尝试从系统的 Python PATH 搜索。如果 import 的模块二次引用其他的 Python 模块实现,则可能导致系统的 Python 模块和虚拟环境中的 Python 模块交叉使用的情况。
在上面的例子中,可以看到 json 模块和实现其部分功能的 _json 模块分别属于系统和虚拟环境。如果系统和虚拟环境中的 Python 版本、模块版本不一致,则很容易导致服务出现问题,并且最重导致 Python 进程本身崩溃,并且很难调试、查找原因。
virtualenv 打包方案从原理上并不可靠
https://blog.csdn.net/weixin_41002327/article/details/112252163
https://blog.csdn.net/yawei_liu1688/article/details/112304595.