如何为Spark Application指定不同的JDK版本详解
前言
随着企业内部业务系统越来越多,基于JVM的服务,通常情况线上环境可能会有多套JDK跑不同的服务。大家都知道基于高版本的Java规范编写的服务跑在低版本的JVM上会出现:java.lang.UnsupportedClassVersionError的异常。
Spark2.2开始移除了对Java7的支持,大多数情况下,我们的SparkApplication是和Hadoop系统公用的JDK,如果Hadoop依赖的JDK版本是7,那我们基于JDK8编写的Application跑在上面就会出问题。
该文主要介绍在不同的场景下,如何为SparkApplication指定不同的JDK版本。
集群已部署了指定的JDK版本
假设集群中每个节点JDK的部署路径为:/usr/java/jdk1.8
Spark提供了spark.executorEnv.[EnvironmentVariableName]配置,可以用来给Executor进程添加环境变量,如果SparkApplication使用的集群管理器是Standalone,只需要通过spark.executorEnv.JAVA_HOME制定Executor端的jdk路径即可,如下:
$SPARK_HOME/bin/spark-submit\ --conf"spark.executorEnv.JAVA_HOME=/usr/java/jdk1.8"\ ...
在YARN模式下,还需要为ApplicationMaster指定不同的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相当于为SparkApplication的Driver设置了特定的JDK版本;
以client的模式部署时,spark.yarn.appMasterEnv.JAVA_HOME仅仅是为ExecutorLauncher设置了特定的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的工作目录下(包括ApplicationMaster的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版本以此类推即可。
注意:由于SparkStandalone没有提供分发JDK安装包并自动解压的功能,所以,这种方式只能用在YARN下。
验证
通过ps-efgrep查询相关进程信息,可以看到java的启动路径为我们特定JDK目录的java表示配置成功。
如下是我在YARN模式下,单独指定JDK版本的Executor的进程启动信息:
stan590751590745020: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%porg.apache.spark.executor.CoarseGrainedExecutorBackend--driver-urlspark://CoarseGrainedScheduler@10.0.0.110:52986--executor-id3--hostnamestan--cores1--app-idapplication_1508397483453_0095--user-class-pathfile:/home/stan/tmp/hadoop-stan/nm-local-dir/usercache/stan/appcache/application_1508397483453_0095/container_1508397483453_0095_01_000004/__app__.jar
附:sparkapplication运行时版本不兼容错误的解决方法
17/06/2714:34:41INFOdeprecation:mapred.map.tasksisdeprecated.Instead,usemapreduce.job.maps 17/06/2714:34:41INFOMemoryStore:Blockbroadcast_0storedasvaluesinmemory(estimatedsize788.8KB,free1246.5MB) 17/06/2714:34:41INFOMemoryStore:Blockbroadcast_0_piece0storedasbytesinmemory(estimatedsize54.0KB,free1246.4MB) 17/06/2714:34:41INFOBlockManagerInfo:Addedbroadcast_0_piece0inmemoryon10.50.70.121:37335(size:54.0KB,free:1247.2MB) 17/06/2714:34:41INFOSparkContext:Createdbroadcast0fromrddatTradeInfoOutlier.scala:30 Exceptioninthread"main"java.lang.NoSuchMethodError:scala.reflect.api.JavaUniverse.runtimeMirror(Ljava/lang/ClassLoader;)Lscala/reflect/api/JavaUniverse$JavaMirror; atcom.fangdd.data.profile.outlier.TradeInfoOutlier$.main(TradeInfoOutlier.scala:30) atcom.fangdd.data.profile.outlier.TradeInfoOutlier.main(TradeInfoOutlier.scala) atsun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethod) atsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) atsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) atjava.lang.reflect.Method.invoke(Method.java:498) atorg.apache.spark.deploy.SparkSubmit$.org$apache$spark$deploy$SparkSubmit$$runMain(SparkSubmit.scala:745) atorg.apache.spark.deploy.SparkSubmit$.doRunMain$1(SparkSubmit.scala:181) atorg.apache.spark.deploy.SparkSubmit$.submit(SparkSubmit.scala:206) atorg.apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:121) atorg.apache.spark.deploy.SparkSubmit.main(SparkSubmit.scala) 17/06/2714:34:42INFOSparkContext:Invokingstop()fromshutdownhook
这种错误是由于生产环境采用的是scala2.10+spark1.6.3的运行环境,本地打的applicationjar使用scala2.11+spark.1.6.3的编译环境,所以放入生产环境集群报了上述错误,更改scala版本重新打jar包后运行成功
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。