[BigData] PySpark on Jupyter Lab
Jupyter Notebook/Lab 是一個常用的互動式介面協助各種程式碼的開發我們在上一篇『建立自己的 Jupyter Notebook 伺服器』有稍微介紹過,一般常見的使用場景是在開發 python 的程式,但是 Jupyter Server 的 Kernel 功能可以擴充更多的互動式開發環境,例如 R, PySpark, SparkR, SparklyR 等等,檸檬爸最早接觸的是將 PySpark 註冊到 Jupyter Lab 裡面,實作的程式碼是透過 AZTK 的 Repository 學習到的,後來進一步將其擴充到 R 等等的使用場景,本篇將會呈現如何部署一個有 PySpark 核心的 Jupyter Lab。
AZTK 驅動包含有 PySpark 的 Jupyter Lab 服務範例
https://github.com/Azure/aztk/blob/master/aztk/spark/models/plugins/jupyter_lab/jupyter_lab.sh
下面的程式碼擷取重要的部分,其中最主要的地方在於:
- 定義 PYSPARK_DRIVER_PYTHON 使 pyspark 程式初始化時驅動 jupyter
- 定義 PYSPARK_DRIVER_PYTHON_OPTS
- 創建一個 kernel.json 檔案
- 利用 pyspark 程式碼啟動
PYSPARK_DRIVER_PYTHON="/opt/conda/bin/jupyter"
JUPYTER_KERNELS="/opt/conda/share/jupyter/kernels"
mkdir $JUPYTER_KERNELS/pyspark
touch $JUPYTER_KERNELS/pyspark/kernel.json
cat << EOF > $JUPYTER_KERNELS/pyspark/kernel.json
{
"display_name": "PySpark",
"language": "python",
"argv": [
"python",
"-m",
"ipykernel",
"-f",
"{connection_file}"
],
"env": {
"SPARK_HOME": "$SPARK_HOME",
"PYSPARK_PYTHON": "python",
"PYSPARK_SUBMIT_ARGS": "--master spark://$MASTER_IP:7077 pyspark-shell"
}
}
EOF
(PYSPARK_DRIVER_PYTHON=$PYSPARK_DRIVER_PYTHON PYSPARK_DRIVER_PYTHON_OPTS="lab --no-browser --port=8889 --allow-root" pyspark &)
缺點:使用以上的方法部署 jupyter notebook 的服務是可以成功的,但是缺點卻也隨之而來,包含 pyspark 綁定了 jupyter,無法在 terminal 的狀態再利用 pyspark 做偵錯,並且進一步限制了 jupyter lab 內部的其他 kernel 必須要同步使用 pyspark,在使用單純 python 的情況下造成資源的浪費。
改良驅動 Jupyter Lab 的方式
為了不要將驅動 pyspark 的方式綁定在 jupyter,我們將 PYSPARK_DRIVER_PYTHON 的定義移進 kernel.json 並且利用定義初始化腳本 PYTHONSTARTUP 的方式做到 SparkSession 的初始化,以下是參考的程式碼:
export JUPYTER_KERNELS=/usr/local/share/jupyter/kernels
mkdir $JUPYTER_KERNELS/pyspark
touch $JUPYTER_KERNELS/pyspark/kernel.json
cat << EOF > $JUPYTER_KERNELS/pyspark/kernel.json
{
"display_name": "PySpark",
"language": "python",
"argv": [
"python",
"-m",
"ipykernel",
"-f",
"{connection_file}"
],
"env": {
"SPARK_HOME": "$SPARK_HOME",
"PYSPARK_PYTHON": "python",
"PYSPARK_DRIVER_PYTHON": "jupyter",
"PYSPARK_SUBMIT_ARGS": "--master spark://$MASTER_IP:7077 pyspark-shell",
"PYTHONSTARTUP": "$JUPYTER_KERNELS/pyspark/init.py"
}
}
EOF
cat << EOF > $JUPYTER_KERNELS/pyspark/init.py
from pyspark.sql import SparkSession
spark = SparkSession.builder.appName("PySpark Kernel").config("spark.master", "spark://$MASTER_IP:7077").getOrCreate()
EOF
jupyter lab --no-browser --port=8999 --allow-root --ip=0.0.0.0 &