坑很多,直接上兼容性最佳的命令,将python包上传到hdfs
或者file:/home/xx/
(此处无多余的/
)
# client 模式
$SPARK_HOME/spark-submit \
--master yarn \
--deploy-mode client \
--num-executors 2 \
--conf "spark.yarn.dist.archives=<Python包路径>/Python包名字.tgz#Python别名" \
--conf "spark.yarn.appMasterEnv.PYSPARK_PYTHON=./Python别名/bin/python" \
本地python路径比如Hello.py
# cluster 模式
$SPARK_HOME/spark-submit \
--master yarn \
--deploy-mode cluster \
--num-executors 2 \
--conf "spark.yarn.dist.archives=<Python包路径>/Python包名字.tgz#Python别名" \
--conf "spark.yarn.appMasterEnv.PYSPARK_PYTHON=./Python别名/bin/python" \
本地python路径比如Hello.py
具体细节
关于 Python包
-
打包可以参考 https://www.jianshu.com/p/d77e16008957,https://blog.csdn.net/sgyuanshi/article/details/114648247 非官方的python,比如anaconda的python可能会有坑,所以最好先用官方版本进行测试
-
此处使用官方2.7.9打包了一个
myPython.tgz
-
这个文件解压 后是
./bin
、lib
、share
等文件夹 -
python
指令在./bin
录下,dddd(懂的都懂) -
myPython.tgz
可以上传到hdfs也可以放在服务器本地
-
-
然后用
archives
参数指向myPython.tgz
,以下2种都可以--conf "spark.yarn.dist.archives=<Python包路径>/Python包名字.tgz#Python别名"
--archives "<Python包路径>/Python包名字.tgz#Python别名"
-
#Python别名
是必须的,比如是#py279
,则YARN会把压缩文件解压到py279
文件夹中,后续就可以直接使用./py279/bin/python
来指向 运行时的python了 -
myPython.tgz
的存放位置- hdfs时基本没有坑,比如是
hdfs://aaa:port/home/xxx/yy/myPython.tgz
- 则上述archive参数为
--archives hdfs://aaa:port/home/xxx/yy/myPython.tgz#py279
- 则上述archive参数为
- 存在本地时,有坑,比如是 在
/home/haha/myPython.tgz
- 则上述archive参数为
--archives file:/home/haha/myPython.tgz#py279
,此处并不是file:///home/hahaxxx
(即正确的形式并没有多余的/
)
- 则上述archive参数为
- hdfs时基本没有坑,比如是
至此,python包已经放好了,也重命名了,比如是存到了hdfs:
--archives "hdfs://aaa:port/home/xxx/yy/myPython.tgz#py279"
然后就需要 driver和executor把python指向上述 python,即py279
关于Driver、Executor指向python
指定Python版本主要有两组参数:小写字母and大写字母;两组参数在使用的时候,根据client模式和cluster模式的不同,会有区别,经过测试,建议使用大写字母
- 小写字母:兼容性较差
- spark.pyspark.driver.python
- spark.pyspark.python
- 大写字母:兼容性较好
spark.yarn.appMasterEnv.PYSPARK_DRIVER_PYTHON
spark.yarn.appMasterEnv.PYSPARK_PYTHON
具体测试结果如下
关于表格中“指本地”、“指集群”、“有无driver路径”的理解,首先简单介绍一下client与cluser模式的区别,这更容易理解。直观的讲:
client模式时,Driver在当前服务器,Executor在集群中,所以Driver的python版本可以指向本地服务器的地址,
而Executor使用的python必须要由上面的参数提交后由YARN发布到各个Executor所在的节点。
cluster模式时,Driver和Executor都在集群中,所以Driver的python也要由YARN通过刚刚的路径提供。
因此,
测试1:client,小写, 有driver路径, 【成功】
$SPARK_HOME/bin/sbmit client \ 其他参数
--archives "hdfs://aaa:port/home/xxx/yy/myPython.tgz#py279" \
--conf "spark.pyspark.driver.python=客户端本地路径如/home/localPython/bin/python" \
--conf "spark.pyspark.python=必须是 ./py279/bin/python" \
本地python路径比如Hello.py
测试2:client, 小写,无driver路径, 【失败 】
$SPARK_HOME/bin/sbmit client \ 其他参数
--archives "hdfs://aaa:port/home/xxx/yy/myPython.tgz#py279" \
--conf "spark.pyspark.python=必须是 ./py279/bin/python" \ # driver的路径已经删了
本地python路径比如Hello.py
测试3:cluster, 小写,指本地,有driver路径, 【失败 】
$SPARK_HOME/bin/sbmit cluster \ 其他参数
--archives "hdfs://aaa:port/home/xxx/yy/myPython.tgz#py279" \
--conf "spark.pyspark.driver.python=客户端本地路径如/home/localPython/bin/python" \
--conf "spark.pyspark.python=必须是 ./py279/bin/python" \
本地python路径比如Hello.py
测试4:cluster, 小写,指集群,有driver路径, 【成功 】
$SPARK_HOME/bin/sbmit cluster \ 其他参数
--archives "hdfs://aaa:port/home/xxx/yy/myPython.tgz#py279" \
--conf "spark.pyspark.driver.python=./py279/bin/python"\ #driver指向了与executor相同python
--conf "spark.pyspark.python=必须是 ./py279/bin/python" \
本地python路径比如Hello.py
大写字母的 spark.yarn.appMasterEnv.PYSPARK_PYTHON
同理,
所以,测试之后,最简单的方案就是文章开头的方案。
如果参数使用不合理,或者打包的python包有问题(比如anaconda的),会报错误如下:
Caused by: java.io.IOException: Cannot run program "/xxxx/xxx/py279/myPy279/bin/python": error=13, Permission denied
Last 4096 bytes of stderr :
eason: User class threw exception: java.io.IOException: Cannot run program "/xxxx/xxx/py279/myPy279/bin/python": error=13, Permission denied
Exception in thread "main" java.io.IOException: Cannot run program "/xxxx/xxx/py279/myPy279/bin/python": error=2, No such file or directory
不是找不到python路径就是权限不够