Py4JError: org.apache.spark.api.python.PythonUtils.getEncryptionEnabled
does not exist in the JVM
SparkSession 을 만들거나 SparkContext 를 초기화하는 순간에 난다.
PySpark 는 파이썬에서 JVM 안의 Spark 객체를 Py4J 로 호출하는 얇은 껍데기다. 이 오류는 파이썬 쪽 PySpark 가 호출하려는 자바 메서드가 실제로 붙은 JVM 클래스패스의 Spark jar 에 없다는 뜻이다. 즉 파이썬 쪽 PySpark 버전과 JVM 쪽 Spark 버전이 다르다.
가장 흔한 경로는 이것이다. 클러스터에 Spark 가 이미 깔려 있는데 pip install pyspark 를 해 버리면, 파이썬은 pip 로 받은 PySpark 를 쓰고 JVM 은 클러스터의 Spark jar 를 쓴다. 두 버전이 다르면 이 오류가 난다.
pyspark --version
spark-submit --version
pip show pyspark | grep -i version
echo "$SPARK_HOME"
echo "$PYTHONPATH"
파이썬 안에서도 확인할 수 있다.
import pyspark, os
print(pyspark.__version__)
print(pyspark.__file__)
print(os.environ.get("SPARK_HOME"))
pyspark.__file__ 이 site-packages 아래를 가리키는데 SPARK_HOME 은 클러스터 설치 경로라면, 그 불일치가 원인이다.
pip 로 받은 PySpark 를 지우고 설치된 Spark 가 제공하는 파이썬 모듈을 쓴다.
pip uninstall -y pyspark
환경변수를 설치 경로에 맞춘다. py4j 의 zip 파일 이름에 버전이 들어 있으므로 실제 파일 이름을 확인해 적는다.
export SPARK_HOME=/opt/spark
ls $SPARK_HOME/python/lib/
export PYTHONPATH=$SPARK_HOME/python:$SPARK_HOME/python/lib/py4j-0.10.9.7-src.zip:$PYTHONPATH
export PATH=$SPARK_HOME/bin:$PATH
findspark 를 쓰면 이 경로 설정을 대신해 준다.
import findspark
findspark.init()
클러스터에 붙지 않고 로컬에서만 쓴다면 pip 로 받은 PySpark 하나만 남기고 SPARK_HOME 을 지운다. 두 개를 동시에 두지 않는 것이 핵심이다.
unset SPARK_HOME
pip install "pyspark==3.5.1"
클러스터 Spark 버전과 같은 PySpark 를 설치한다.
pip install "pyspark==$(spark-submit --version 2>&1 | grep -oP 'version \K[0-9.]+' | head -1)"
드라이버와 익스큐터가 서로 다른 파이썬을 쓰면 다른 오류가 난다. 명시적으로 지정한다.
export PYSPARK_PYTHON=/usr/bin/python3
export PYSPARK_DRIVER_PYTHON=/usr/bin/python3
주피터에서 쓰려고 PYSPARK_DRIVER_PYTHON=jupyter 로 설정해 둔 환경이 남아 있으면 spark-submit 이 이상하게 동작한다. 배치 실행 전에는 비운다.
Cloudera 같은 배포판은 자체 Spark 를 패키징한다. 이 경우 pip 로 받은 PySpark 는 거의 항상 충돌한다. 배포판이 제공하는 실행 스크립트를 쓴다.
spark-submit --master yarn --deploy-mode client example.py
Kerberos 클러스터라면 프린시펄과 키탭을 준다.
spark-submit --master yarn \
--principal user@EXAMPLE.COM \
--keytab /path/to/user.keytab \
example.py
파이썬 의존성은 클러스터 전 노드에 있어야 한다. 없으면 --archives 로 가상환경을 배포하거나 배포판의 런타임 이미지 기능을 쓴다.
pip show pyspark 를 직접 확인한다.PYTHONPATH 에 py4j zip 을 넣을 때 파일 이름의 버전을 실제 파일에서 확인한다. 예제의 버전을 그대로 붙여 넣으면 경로가 없어 임포트에 실패한다.