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', <function subimport at 0x7fdb333fdb18>, ('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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章