如何在 PySpark 中管理 Python 相依性套件
在分散式運算環境中控制一個應用程式的環境通常相當有挑戰性。確保所有節點有需要的環境可以執行並不會太簡單,能掌握使用者的程式碼實際在哪個地方跑有些時候是需要點技巧的。
Apache Spark™ 透過腳本選項提供了許多標準方法,在一個叢集裡橫跨多個節點去管理相依性(程式碼套件),像是--jars
、 --packages
、和諸如spark.jars.*
的設置,確保使用者能在他們的叢集裡頭行雲流水地管理那些相依性。
另一方面來說,PySpark 的使用者常會詢問如何對 Python 的相依性做到同樣的事,有許多張票(JIRA issue)如 SPARK-13587 、SPARK-16367、SPARK-20001、和 SPARK-25433 都在討論這件事。一個能描繪相依性管理情境的簡單例子就是使用者在執行 pandas UDFs (自定義函式)的時候。
如果他們不能將所需的相依性安裝在所有其它節點上,Spark 運算引擎就會報錯然後跟你說 PyArrow 和 pandas 需要被安裝。
一個直接的方式就是使用像是 --py-files
的腳本選項或是 spark.submit.pyFiles
設定,但是這項功能並不能解決諸如安裝 wheel 檔案或是當 Python 套件是建立在 C 和 C++ 之上,如 pyarrow 與 NumPy ,的這些情景裡頭。
這篇部落格文章要介紹如何在 Apache Spark 裡面全方位地控制 Python 相依性(程式碼套件)。大部分的內容也會在要來的 Apache Spark 3.1 中作爲禪計畫(Project Zen)被記錄在文件裡頭。你可以到《禪計畫更新:為 Python 使用者改善 Apache Spark 》(Project Zen: Improving Apache Spark for Python Users)這部影片中了解更多細節。
使用 Conda
Conda 是最被廣為使用的 Python 套件管理系統。PySpark 使用者可以直接使用 Conda 環境借助 conda-pack 去輸送他們的第三方 Python 套件,conda-pack 是一種能建立可重複移動的 Conda 環境的命令列工具。它會在要來的 Apache Spark 3.1 中支援於所有類型的叢集裡面。在 Apache Spark 3.0 或是較低的版本裡面,它只能在 YARN 模式中被使用。
下面這個例子建立了一個能在驅動者(driver)和執行者(executor)中使用的 Conda 環境並將這個環境封裝到一個歸檔文件裡面。這個歸檔文件捕捉了 Python 的 Conda 環境並儲存了 Python 編譯器和所有相關的相依性套件。
在那之後,你能夠以腳本或是在程式碼中使用 --archives
選項或是 spark.archives
設定一起運送(YARN模式是spark.yarn.dist.archives
)。它能在執行者上自動解開歸檔文件。
在 spark-submit
腳本的例子裡頭,你能夠如下面的範例使用它:
注意,上頭的 PYSPARK_DRIVER_PYTHON
不能在 YARN 模式或是 Kubernetes 模式中設定成叢集模式。
pyspark
殼層(shell):
如果你在常規的 Python 殼層(shell)中或是筆記本(Jupyter notebook)裡面,你可以如下面所展示的去試一試:
使用 Virtualenv
Virtualenv 是一款建立獨立 Python 環境的 Python 工具。從 Python 3.3 開始,它部分的功能就已經作為一個標準程式庫(library)在 venv 模組中被整合進 Python 裡面。在要來的 Apache Spark 3.1 中,PySpark 使用者就能夠使用 virtualenv 在叢集裡面以 venv-pack 透過類似 conda-pack 的方式去管理 Python 相依性。在 Apache Spark 3.0 或是較低的版本裡面,它只能在 YARN 模式中被使用。
在驅動者和執行者中皆能使用的虛擬環境能夠如下所展示的去建立。virtualenv 封裝了現存的虛擬環境到一個歸檔文件當中,它包含了 Python 編譯器和相依性。然而,這種方式會需要一個叢集裏的所有節點有相同的 Python 編譯器,因為 venv-pack 將 Python 編譯器封裝成軟連結(symbolic link)。
你可以借助--archives
選項或是spark.archives
設定(YARN模式是spark.yarn.dist.archives
)在執行者上直接傳遞/打開歸檔文件。
對spark-submit
來說,你能夠藉由執行下面的指令使用環境。另外,注意到 PYSPARK_DRIVER_PYTHON
在 Kubernetes 或是 YARN 模式中需要被清除。
在 pyspark
殼層的情境裡:
Python 殼層或是筆記本:
使用 PEX
PySpark 也能夠使用 PEX 一起輸送 Python 套件。PEX 是款能夠建立自包含 Python 環境的工具。它和 Conda 或是 virtualenv 相似,但 .pex
檔案本身是可以執行的。
下面例子建立了 .pex
檔案給驅動者和執行者使用,該檔案包含了透過 pex
指令定義的 Python 相依性。
這個檔案就和一般的 Python 編譯器運作的相當類似。
然而,.pex
檔案本質上本身不能包 Python 編譯器,所以一個叢集裡面所有節點需要有同樣版本的 Python 編譯器被安裝。
為了在叢集裡轉移並使用 .pex
檔案,你需要透過 spark.files
設定(YARN模式是spark.yarn.dist.archives
)或是--files
選項去運送它,因為它們是一般的檔案而不是目錄或是歸檔文件。
針對應用程式遞交,你可以執行如下面的指令。 PYSPARK_DRIVER_PYTHON
不能在 YARN 模式或是 Kubernetes 模式中設定成叢集模式。
而互動式 pyspark
殼層,指令幾乎是一樣:
一般的 Python 殼層或是筆記本:
結論
在 Apache Spark 中,Conda、virtualenv 和 PEX 能被借來運送和管理 Python 相依性。
- Conda:這是其中一個最被廣為使用的套件管理系統。在 Apache Spark 3.0 和較低的版本裡面,Conda 只有在 YARN 叢集中被支援,而它在要來的 Apacher Spark 3.1 中能夠在所有種類的叢集類型中運作。
- Virtualenv:使用者不用透過額外的安裝就能使用它,因為它在 Python 中是內建的程式庫,但它會需要所有節點中都裝有相同的 Python 而 Conda 並不需要。 Virtualenv 在 Apache Spark 3.0 和較低的版本裡面,只能在 YARN 叢集中可以運作,而要來的 Apache Spark 3.1 中,所有其它叢集類型都支援 Virtualenv 。
- PEX:它在任何 Apache Spark 版本、任何叢集類型都能夠被使用,雖然它可以說是沒被那麼廣泛地被使用而且需要在所有節點中裝有相同的 Python 而 Conda 不需要。
在 Apache Spark 中、 Conda、virtualenv、和 PEX 能夠被借助來運送和管理 Python 相依性。
註記
此篇文章作者為 Hyukjin Kwon ,於 2020 年 12 月 22 日撰寫於 Databricks 的工程部落格裡面。有需要的人,可以從這裏閱讀原文——How to Manage Python Dependencies in PySpark — — 。