Oozie 워크플로의 Spark 액션이 Spark 2 를 바라본다. Scala 2.12 로 빌드한 Spark 3 잡을 돌려야 한다.
CDP 는 Spark 3 전용 액션을 제공한다. XML 태그 이름부터 다르다. 기존 <spark> 대신 <spark3> 을 쓴다. Spark 2 가 단종되면서 기존 Spark 액션은 기본적으로 비활성 상태이므로, Spark 3 을 쓰려면 이 액션으로 옮긴다.
<action name="spark3-action">
<spark3 xmlns="uri:oozie:spark-action:1.0">
<resource-manager>${resourceManager}</resource-manager>
<name-node>${nameNode}</name-node>
<master>yarn</master>
<mode>cluster</mode>
<name>My Spark3 Job</name>
<class>com.example.MySparkJob</class>
<jar>${nameNode}/user/spark/my-spark-job.jar</jar>
<spark-opts>--executor-memory 4G --num-executors 4</spark-opts>
</spark3>
<ok to="end"/>
<error to="fail"/>
</action>
master 와 mode 는 함께 지정해야 한다. master=yarn 이면 mode 는 cluster 또는 client 중 하나여야 한다.
Oozie 는 액션이 쓸 라이브러리를 HDFS 의 ShareLib 에 두고 배포한다. Spark 3 ShareLib 은 Oozie 빌드 시점에 만들어지므로, Spark 3 parcel 을 올리면 ShareLib 도 갱신해야 한다. Cloudera Manager 에는 Update the Spark3 ShareLib 동작이 있어 다른 ShareLib 은 그대로 두고 Spark 3 부분만 교체한다. 기본적으로 현재 활성화된 Spark 3 parcel 을 가리키는 SPARK3 심볼릭 링크를 사용한다.
직접 관리하는 환경에서는 HDFS 경로에 라이브러리를 올리고 갱신한다.
hdfs dfs -ls /user/oozie/share/lib/
oozie admin -oozie http://oozie-server:11000/oozie -sharelibupdate
oozie admin -oozie http://oozie-server:11000/oozie -shareliblist
oozie job -oozie http://oozie-server:11000/oozie -config job.properties -run
oozie job -oozie http://oozie-server:11000/oozie -info <job-id>
oozie job -oozie http://oozie-server:11000/oozie -log <job-id>
java.lang.reflect.InvocationTargetException 은 껍데기다. 실제 원인은 그 아래 Caused by 에 있다. Oozie 런처의 YARN 로그를 받아 원문을 본다.
yarn logs -applicationId <launcher-appId> | grep -A 30 'Caused by'
java.lang.AbstractMethodError 나 NoSuchMethodError 는 라이브러리 버전이 섞였다는 신호다. ShareLib 에 Spark 2 와 Spark 3 의 JAR 이 함께 있거나, 애플리케이션 JAR 이 다른 버전의 Spark 를 포함한 경우다. fat JAR 을 만들 때 Spark 의존성은 provided 로 두어 포함하지 않는다.
spark.yarn.jars 는 대체로 설정할 필요가 없다. Spark 2 이후로는 필요한 JAR 을 자동으로 배포하며, 잘못 지정하면 오히려 버전이 섞인다. 매번 업로드하는 시간을 줄이려는 목적이라면 HDFS 에 올려 둔 경로를 지정하되 Spark 버전과 정확히 일치시켜야 한다.