Amazon EMR에서 Spark의 "java.lang.ClassNotFoundException"을 해결하려면 어떻게 해야 하나요?

최종 업데이트 날짜: 2022년 3월 2일

Amazon EMR에서 spark-submit 또는 PySpark 작업에 사용자 지정 JAR 파일을 사용하면 java.lang.ClassNotFoundException 오류가 발생합니다.

간략한 설명

이 오류는 다음 조건 중 하나가 참일 때 발생합니다.

  • spark-submit 작업의 클래스 경로에서 관련 파일을 찾을 수 없습니다.
  • 부트스트랩 작업 또는 사용자 지정 구성이 클래스 경로를 덮어씁니다. 이 경우 클래스 로더는 사용자가 구성에서 지정한 위치에 있는 JAR 파일만 사용합니다.

해결 방법

스택 추적을 확인하여 누락된 클래스의 이름을 찾습니다. 그런 다음 사용자 지정 JAR의 경로(누락된 클래스 포함)의 경로를 Spark 클래스 경로에 추가합니다. 클러스터 실행 중에, 새 클러스터를 시작할 때 또는 작업을 제출할 때 경로를 추가할 수 있습니다.

실행 중인 클러스터의 경우

/etc/spark/conf/spark-defaults.conf에서 사용자 지정 JAR의 경로를 오류 스택 추적에 지정된 클래스 이름에 추가합니다. 다음 예에서 /home/hadoop/extrajars/*는 사용자 지정 JAR 경로입니다.

sudo vim /etc/spark/conf/spark-defaults.conf
spark.driver.extraClassPath <other existing jar locations>:/home/hadoop/extrajars/*
spark.executor.extraClassPath <other existing jar locations>:/home/hadoop/extrajars/*

새 클러스터의 경우

클러스터를 생성할 때 구성 객체를 제공하여 사용자 지정 JAR 경로를 /etc/spark/conf/spark-defaults.conf의 기존 클래스 경로에 추가합니다.

참고: 이 옵션을 사용하려면 Amazon EMR 릴리스 버전 5.14.0 이상을 사용하여 클러스터를 생성해야 합니다.

아마존 EMR 5.14.0에서 아마존 EMR 5.17.0으로의 경우 다음을 포함합니다.

[
  {
    "Classification": "spark-defaults",
    "Properties": {
      "spark.driver.extraClassPath": "/usr/lib/hadoop-lzo/lib/*:/usr/lib/hadoop/hadoop-aws.jar:/usr/share/aws/aws-java-sdk/*:/usr/share/aws/emr/emrfs/conf:/usr/share/aws/emr/emrfs/lib/*:/usr/share/aws/emr/emrfs/auxlib/*:/usr/share/aws/emr/security/conf:/usr/share/aws/emr/security/lib/*:/usr/share/aws/hmclient/lib/aws-glue-datacatalog-spark-client.jar:/usr/share/java/Hive-JSON-Serde/hive-openx-serde.jar:/usr/share/aws/sagemaker-spark-sdk/lib/sagemaker-spark-sdk.jar:/home/hadoop/extrajars/*",
      "spark.executor.extraClassPath": "/usr/lib/hadoop-lzo/lib/*:/usr/lib/hadoop/hadoop-aws.jar:/usr/share/aws/aws-java-sdk/*:/usr/share/aws/emr/emrfs/conf:/usr/share/aws/emr/emrfs/lib/*:/usr/share/aws/emr/emrfs/auxlib/*:/usr/share/aws/emr/security/conf:/usr/share/aws/emr/security/lib/*:/usr/share/aws/hmclient/lib/aws-glue-datacatalog-spark-client.jar:/usr/share/java/Hive-JSON-Serde/hive-openx-serde.jar:/usr/share/aws/sagemaker-spark-sdk/lib/sagemaker-spark-sdk.jar:/home/hadoop/extrajars/*"
    }
  }
]

아마존 EMR 5.17.0에서 아마존 EMR 5.18.0으로의 경우 추가 JAR 경로로 /usr/share/aws/emr/s3select/lib/emr-s3-select-spark-connector.jar를 포함합니다.

[
  {
    "Classification": "spark-defaults",
    "Properties": {
      "spark.driver.extraClassPath": "/usr/lib/hadoop-lzo/lib/*:/usr/lib/hadoop/hadoop-aws.jar:/usr/share/aws/aws-java-sdk/*:/usr/share/aws/emr/emrfs/conf:/usr/share/aws/emr/emrfs/lib/*:/usr/share/aws/emr/emrfs/auxlib/*:/usr/share/aws/emr/security/conf:/usr/share/aws/emr/security/lib/*:/usr/share/aws/hmclient/lib/aws-glue-datacatalog-spark-client.jar:/usr/share/java/Hive-JSON-Serde/hive-openx-serde.jar:/usr/share/aws/sagemaker-spark-sdk/lib/sagemaker-spark-sdk.jar:/usr/share/aws/emr/s3select/lib/emr-s3-select-spark-connector.jar:/home/hadoop/extrajars/*",
      "spark.executor.extraClassPath": "/usr/lib/hadoop-lzo/lib/*:/usr/lib/hadoop/hadoop-aws.jar:/usr/share/aws/aws-java-sdk/*:/usr/share/aws/emr/emrfs/conf:/usr/share/aws/emr/emrfs/lib/*:/usr/share/aws/emr/emrfs/auxlib/*:/usr/share/aws/emr/security/conf:/usr/share/aws/emr/security/lib/*:/usr/share/aws/hmclient/lib/aws-glue-datacatalog-spark-client.jar:/usr/share/java/Hive-JSON-Serde/hive-openx-serde.jar:/usr/share/aws/sagemaker-spark-sdk/lib/sagemaker-spark-sdk.jar:/usr/share/aws/emr/s3select/lib/emr-s3-select-spark-connector.jar:/home/hadoop/extrajars/*"
    }
  }
]

아마존 EMR 5.19.0에서 아마존 EMR 5.32.0으로의 경우 다음과 같이 JAR 경로를 업데이트합니다.

[
  {
    "Classification": "spark-defaults",
    "Properties": {
      "spark.driver.extraClassPath": "/usr/lib/hadoop-lzo/lib/*:/usr/lib/hadoop/hadoop-aws.jar:/usr/share/aws/aws-java-sdk/*:/usr/share/aws/emr/emrfs/conf:/usr/share/aws/emr/emrfs/lib/*:/usr/share/aws/emr/emrfs/auxlib/*:/usr/share/aws/emr/goodies/lib/emr-spark-goodies.jar:/usr/share/aws/emr/security/conf:/usr/share/aws/emr/security/lib/*:/usr/share/aws/hmclient/lib/aws-glue-datacatalog-spark-client.jar:/usr/share/java/Hive-JSON-Serde/hive-openx-serde.jar:/usr/share/aws/sagemaker-spark-sdk/lib/sagemaker-spark-sdk.jar:/usr/share/aws/emr/s3select/lib/emr-s3-select-spark-connector.jar:/home/hadoop/extrajars/*",
      "spark.executor.extraClassPath": "/usr/lib/hadoop-lzo/lib/*:/usr/lib/hadoop/hadoop-aws.jar:/usr/share/aws/aws-java-sdk/*:/usr/share/aws/emr/emrfs/conf:/usr/share/aws/emr/emrfs/lib/*:/usr/share/aws/emr/emrfs/auxlib/*:/usr/share/aws/emr/goodies/lib/emr-spark-goodies.jar:/usr/share/aws/emr/security/conf:/usr/share/aws/emr/security/lib/*:/usr/share/aws/hmclient/lib/aws-glue-datacatalog-spark-client.jar:/usr/share/java/Hive-JSON-Serde/hive-openx-serde.jar:/usr/share/aws/sagemaker-spark-sdk/lib/sagemaker-spark-sdk.jar:/usr/share/aws/emr/s3select/lib/emr-s3-select-spark-connector.jar:/home/hadoop/extrajars/*"
    }
  }
]

아마존 EMR 5.33.0에서 아마존 EMR 5.34.0으로의 경우 다음과 같이 JAR 경로를 업데이트합니다.

[
  {
    "Classification": "spark-defaults",
    "Properties": {
      "spark.driver.extraClassPath": "/usr/lib/hadoop-lzo/lib/*:/usr/lib/hadoop/hadoop-aws.jar:/usr/share/aws/aws-java-sdk/*:/usr/share/aws/emr/goodies/lib/emr-spark-goodies.jar:/usr/share/aws/emr/security/conf:/usr/share/aws/emr/security/lib/*:/usr/share/aws/hmclient/lib/aws-glue-datacatalog-spark-client.jar:/usr/share/java/Hive-JSON-Serde/hive-openx-serde.jar:/usr/share/aws/sagemaker-spark-sdk/lib/sagemaker-spark-sdk.jar:/usr/share/aws/emr/s3select/lib/emr-s3-select-spark-connector.jar:/home/hadoop/extrajars/",
      "spark.executor.extraClassPath": "/usr/lib/hadoop-lzo/lib/*:/usr/lib/hadoop/hadoop-aws.jar:/usr/share/aws/aws-java-sdk/*:/usr/share/aws/emr/goodies/lib/emr-spark-goodies.jar:/usr/share/aws/emr/security/conf:/usr/share/aws/emr/security/lib/*:/usr/share/aws/hmclient/lib/aws-glue-datacatalog-spark-client.jar:/usr/share/java/Hive-JSON-Serde/hive-openx-serde.jar:/usr/share/aws/sagemaker-spark-sdk/lib/sagemaker-spark-sdk.jar:/usr/share/aws/emr/s3select/lib/emr-s3-select-spark-connector.jar:/home/hadoop/extrajars/"
    }
  }
]

Amazon EMR 릴리스 버전 6.0.0 이상의 경우 구성을 사용한 JAR 경로 업데이트가 작동하지 않습니다. 이러한 버전의 경우.conf 파일에는 여러 jar 파일 경로가 포함됩니다. 또한 업데이트하는 각 속성의 구성 길이는 1024자를 초과할 수 없습니다. 그러나 부트스트랩 작업을 추가하여 사용자 정의 JAR 위치를 spark-defaults.conf에 전달할 수 있습니다. 자세한 내용은 부트스트랩 단계 후에 모든 Amazon EMR 노드를 업데이트하려면 어떻게 해야 하나요?를 참조하세요.

다음과 유사한 bash 스크립트를 생성합니다.

참고:

  • s3: //doc-example-bucket/Bootstraps/script_b.sh를 선택한 Amazon Simple Storage Service(Amazon S3) 경로로 바꿔야 합니다.
  • /home/hadoop/extrajars/*를 사용자 정의 JAR 파일 경로로 바꿔야 합니다.
  • Amazon EMR 실행 역할에 이 S3 버킷에 액세스할 수 있는 권한이 있는지 확인합니다.
#!/bin/bash
#
# This is an example of script_b.sh for changing /etc/spark/conf/spark-defaults.conf
#
while [ ! -f /etc/spark/conf/spark-defaults.conf ]
do
  sleep 1
done
#
# Now the file is available, do your work here
#
sudo sed -i '/spark.*.extraClassPath/s/$/:\/home\/hadoop\/extrajars\/\*/' /etc/spark/conf/spark-defaults.conf
exit 0

EMR 클러스터를 시작하고 다음과 유사한 부트스트랩 작업을 추가합니다.

#!/bin/bash
pwd
aws s3 cp s3://doc-example-bucket/Bootstraps/script_b.sh .
chmod +x script_b.sh
nohup ./script_b.sh &

단일 작업의 경우

spark-submit 실행 시에 --jars 옵션을 사용하여 사용자 지정 JAR 경로를 전달합니다.

예:

spark-submit --deploy-mode client --class org.apache.spark.examples.SparkPi --master yarn spark-examples.jar 100 --jars /home/hadoop/extrajars/*

참고: 클래스 충돌을 방지하려면 --jars 옵션을 사용할 때 표준 JAR을 포함하지 마세요. 예를 들어 spark-core.jar는 클러스터에 이미 있으므로 포함해서는 안 됩니다.

구성 클래스 분류에 대한 자세한 내용은 Spark 구성을 참조하세요.