隨着企業內部業務系統越來越多,基於JVM的服務,通常情況線上環境可能會有多套JDK跑不同的服務。大家都知道基於高版本的Java規范編寫的服務跑在低版本的JVM上會出現:java.lang.UnsupportedClassVersionError
的異常。
Spark 2.2開始移除了對Java 7的支持,大多數情況下,我們的Spark Application是和Hadoop系統公用的JDK,如果Hadoop依賴的JDK版本是7,那我們基於JDK 8編寫的Application跑在上面就會出問題。
該文主要介紹在不同的場景下,如何為Spark Application指定不同的JDK版本。
集群已部署了指定的JDK版本
假設集群中每個節點JDK的部署路徑為:/usr/java/jdk1.8
Spark提供了spark.executorEnv.[EnvironmentVariableName]配置,可以用來給Executor進程添加環境變量,如果Spark Application使用的集群管理器是Standalone,只需要通過spark.executorEnv.JAVA_HOME制定Executor端的jdk路徑即可,如下:
$SPARK_HOME/bin/spark-submit \
--conf "spark.executorEnv.JAVA_HOME=/usr/java/jdk1.8" \
...
在YARN模式下,還需要為Application Master指定不同的JAVA_HOME環境變量,如下:
$SPARK_HOME/bin/spark-submit \
--conf "spark.executorEnv.JAVA_HOME=/usr/java/jdk1.8" \
--conf "spark.yarn.appMasterEnv.JAVA_HOME=/usr/java/jdk1.8" \
...
以cluster的方式部署在YARN上的時候,spark.yarn.appMasterEnv.JAVA_HOME
相當於為Spark Application的Driver設置了特定的JDK版本;
以client的模式部署時,spark.yarn.appMasterEnv.JAVA_HOME
僅僅是為Executor Launcher設置了特定的JDK版本。
Driver端的JDK版本和spark-submit所在的機器中的SPARK_HOME環境變量一致,直接在spark-env.sh中指定即可。
集群缺失特定的JDK版本,且對集群無管理權限
某些特殊的場景下,我們對集群沒有管理權限,只能通過YARN提交Application,並且集群里沒有部署我們需要的JDK版本,這種情形就需要將JDK的安裝包也一並提交了。
這里要求我們的JDK安裝包必須為gz格式的,和你代碼打包后的jar包放在同一目錄下,假設我們下載的JDK的安裝包為:jdk-8u141-linux-x64.tar.gz。
關鍵配置如下:
$SPARK_HOME/bin/spark-submit \
--conf "spark.yarn.dist.archives=jdk-8u141-linux-x64.tar.gz" \
--conf "spark.executorEnv.JAVA_HOME=./jdk-8u141-linux-x64.tar.gz/jdk1.8.0_141" \
--conf "spark.yarn.appMasterEnv.JAVA_HOME=./jdk-8u141-linux-x64.tar.gz/jdk1.8.0_141" \
...
我們可以通過指定spark.yarn.dist.archives
配置,將JDK的安裝包分發到所有Executor的工作目錄下(包括Application Master的Executor),另外tar.gz的壓縮包也會被自動解壓,假設jdk-8u141-linux-x64.tar.gz
解壓后的目錄為jdk1.8.0_141
,那么我們特定的JDK的目錄就是:./jdk-8u141-linux-x64.tar.gz/jdk1.8.0_141
,不同的JDK版本以此類推即可。
注意:由於Spark Standalone沒有提供分發JDK安裝包並自動解壓的功能,所以,這種方式只能用在YARN下。
驗證
通過ps -ef
grep查詢相關進程信息,可以看到java的啟動路徑為我們特定JDK目錄的java表示配置成功。
如下是我在YARN模式下,單獨指定JDK版本的Executor的進程啟動信息:
stan 590751 590745 0 20:45 ? 00:00:14 ./jdk-8u141-linux-x64.tar.gz/jdk1.8.0_141/bin/java -server -Xmx512m -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+G1SummarizeConcMark -XX:InitiatingHeapOccupancyPercent=35 -XX:PermSize=256M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:./gc.log -verbose:gc -Djava.io.tmpdir=/home/stan/tmp/hadoop-stan/nm-local-dir/usercache/stan/appcache/application_1508397483453_0095/container_1508397483453_0095_01_000004/tmp -Dspark.driver.port=52986 -Dspark.yarn.app.container.log.dir=/home/stan//hadoop-2.6.4/logs/userlogs/application_1508397483453_0095/container_1508397483453_0095_01_000004 -XX:OnOutOfMemoryError=kill %p org.apache.spark.executor.CoarseGrainedExecutorBackend --driver-url spark://CoarseGrainedScheduler@10.0.0.110:52986 --executor-id 3 --hostname stan --cores 1 --app-id application_1508397483453_0095 --user-class-path file:/home/stan/tmp/hadoop-stan/nm-local-dir/usercache/stan/appcache/application_1508397483453_0095/container_1508397483453_0095_01_000004/__app__.jar