spark教程-Pyspark On Yarn 的模塊依賴問題


原理簡述

Yarn 模式是把資源統一交給 Yarn 集群來管理,其優點在於實現了 application 的多樣性,如 MapReduce 程序、HBase 集群、Storm 集群、spark 集群等;

Yarn 模式有兩種運行模式:client 和 cluster,區別在於 

client 模式的 Driver 運行在 client 端,而 client 端可能是 spark 集群內節點,也可以不是,一般來說不是集群內節點,這就需要在客戶端節點上安裝程序運行所需環境,以支持 spark 的正常執行;

cluster 模式的 Driver 運行在 spark 集群中的某個 NodeManager 上,而且不確定到底是哪個 NodeManager 上,這由 spark 的調度策略決定,

如果知道了在哪個節點,在該節點上安裝程序運行所需環境即可,

但是事實是哪個節點都有可能,這意味着需要在所有節點上安裝程序運行所需環境,顯然這不是個好辦法;

 

隨着 application 的增加,需要不斷安裝新的包,而且不同 application 可能存在版本問題,這對於 client 模式來說或許還可以接受,但 cluster 模式肯定不行的,如果集群很大,裝環境就會死人的

 

一句通俗的話描述 Pyspark On Yarn:Driver 從本地電腦獲取環境后分發給 Container 來執行

 

問題復現

下面用一個小例子測試下 Yarn 的 模塊依賴問題

主函數

from pyspark import SparkContext
from dependency.mydata import data      # 自己寫的模塊

sc = SparkContext(master='yarn', appName='yilai')
out = sc.parallelize(data)
out.saveAsTextFile('/spark/out')

自己寫的模塊 dependency/mydata.py,這個模塊被主函數依賴

data = range(100)

 

運行結果

spark-submit --master yarn --deploy-mode client --py-files dep.zip mySparkCode.py     # 可以執行
spark-submit --master yarn --deploy-mode cluster --py-files dep.zip mySparkCode.py    # 可以執行,而且 關掉 client 可執行

spark-submit --master yarn --deploy-mode client mySparkCode.py    # 可以執行
spark-submit --master yarn --deploy-mode cluster mySparkCode.py   # 不可以執行

--py-files 什么意思,我后面解釋,它的作用就是把自寫模塊打包給 Driver;

在有 --py-files 的情況下,client 和 cluster 模式都可以執行,畢竟都打包上傳了,可以理解;

在沒有 --py-files 的情況下,client 模式可以運行,而且只要 dependency 放在 PYTHONPATH 的環境變量里,都可以運行,而 cluster 模式下不可執行;

 

原因解析

1. 被提交的任務放在 clien 端,被依賴的模塊也在 client 端

2. client 模式下,Driver 運行在 client 上,Driver 可以找到被依賴的包,並發送給 Container

3. cluster 模式下,Driver 運行在 NodeManager 上,Driver 找不到被依賴的包,報錯,Container exited with a non-zero exit code 13

 

而且經過我測試,自寫模塊存在鏈式依賴也可以執行,但是調用第三方模塊如 numpy 就不行了  【site-packages 下的模塊】

異常信息為 

ImportError: No module named xxx

 

解決方案

模塊依賴也可以分為多種情景:

有簡單依賴,如單文件依賴,也有復雜依賴,如依賴多個文件,甚至 鏈式依賴,如代碼依賴 padans,而 pandas 依賴 numpy

 

普通依賴

普通依賴有兩種解決方法,當然這兩種方法也可以解決部分 復雜依賴 問題,是通用的方法

--py-files

它是 spark-submit 的參數,官方解釋如下

Comma-separated list of .zip, .egg, or .py files to place on the PYTHONPATH for Python apps.   
Comma,逗號;separated 分隔;                             

 用逗號分隔的 zip、egg、py 文件列表來代替 PYTHONPATH 環境變量

 

如果依賴單個文件,直接寫文件名即可,

spark-submit --master yarn --deploy-mode cluster --py-files xxx.py mySparkCode.py

如果是多個文件,用逗號隔開,

如果是一個包,需要進行壓縮打包    【自己寫的包】

復制代碼
[root@hadoop10 ~]# cd /usr/lib/python27/
[root@hadoop10 python27]# ls
bin  dependency  include  lib  share
[root@hadoop10 python27]# zip -r dep.zip dependency/
  adding: dependency/ (stored 0%)
  adding: dependency/__init__.py (stored 0%)
  adding: dependency/mydata.py (stored 0%)
復制代碼

效果如圖

然后執行命令

spark-submit --master yarn --deploy-mode cluster --py-files /usr/lib/python27/dep.zip mySparkCode.py

注意,壓縮文件必須是全路徑,即使它在 PYTHONPATH 環境變量內,不寫全路徑也會報錯 file do not exist

 

addPyFile

在代碼內部解決問題,很簡單,只需要一句

sc.addPyFile(file_path)

 

第三方依賴

以 numpy、pandas 為代表的第三方依賴比較麻煩,解決方案如下

1)創建 python 虛擬環境,並在虛擬環境中安裝各種需要的包

參考我的博客 python 虛擬環境

值得注意的是,可能要使用 pip install --ignore-installed 來強行安裝

2)壓縮整個虛擬環境

注意是壓縮整個環境,而不是被安裝的包

[root@hadoop10 lib]# zip -r py.zip pyspark-ml-env/

pyspark-ml-env 是虛擬環境的目錄

3)將虛擬環境壓縮包上傳 hdfs

[root@hadoop10 spark]# hadoop fs -put /usr/lib/py.zip /spark/env

4)以 numpy 為例,編寫測試代碼

import numpy as np
from pyspark import SparkContext

sc = SparkContext(master='yarn', appName='test_use_numpy')
rdd = sc.parallelize(np.arange(100))
rdd.saveAsTextFile('/spark/numpy_test')

5)執行如下命令運行代碼

注意是 cluster 模式,client 模式不用這么麻煩

spark-submit
--master yarn 
--deploy-mode cluster
--conf spark.yarn.dist.archives=hdfs:///spark/env/py.zip#pyenv
--conf spark.yarn.appMasterEnv.PYSPARK_PYTHON=pyenv/pyspark-ml-env/bin/python
regression_metrics.py

spark.yarn.dist.archives:hdfs:///spark/env/py.zip 指定壓縮文件地址,壓縮文件被分發到 executor 上,並且解壓,#pyenv 代表解壓到的目錄

spark.yarn.appMasterEnv.PYSPARK_PYTHON:指定使用的 python 環境;pyenv 即上面的解壓目錄,pyspark-ml-env 即創建的虛擬環境的目錄

 

6)查看結果

 

 運行正常

 

總結

下面我把 模塊依賴 的使用問題進行一下總結

1. Driver 負責把本地的資源分發給 Container

2. 在 client 模式下,Driver 就找在 Client 端,可以把 client 端的資源分發,而 cluster 模式下,Driver 可在集群任一節點,該節點是沒有資源的

3. 如果是 普通依賴:

在 client 模式下,Driver 可能自動收集資源,分發,無需上傳依賴;

在 cluster 模式下,Driver 無法收集資源,必須上傳依賴;

4. 如果是 復雜依賴:

在 client 模式 和 cluster 模式下,都需要通過 虛擬環境 上傳依賴

5. 在工業環境中,使用的多是 cluster 模式,cluster 模式必須上傳依賴

6. 在調試環節,多使用 client 模式,client 只需上傳復雜依賴即可

 

 

 

參考資料:

https://blog.csdn.net/github_38358734/article/details/78292696  講了點原理,作用不大

https://www.cnblogs.com/nucdy/p/8569606.html  和上個鏈接大同小異

https://blog.csdn.net/wangxiao7474/article/details/81391300  常規方法總結

https://zhuanlan.zhihu.com/p/43434216  知乎,說得挺詳細,此篇是我唯一實驗 numpy 等復雜依賴 成功的教程

https://www.cnblogs.com/piperck/p/10121097.html  這篇和上面 知乎 那篇雷同

https://www.jianshu.com/p/df0a189ff28b  numpy 等復雜模塊的解決方案

https://www.jianshu.com/p/0787b4641b23


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM