欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

如何为Spark Application指定不同的JDK版本详解

程序员文章站 2024-02-26 15:01:28
前言 随着企业内部业务系统越来越多,基于jvm的服务,通常情况线上环境可能会有多套jdk跑不同的服务。大家都知道基于高版本的java规范编写的服务跑在低版本的jvm上会出...

前言

随着企业内部业务系统越来越多,基于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

附:spark application运行时版本不兼容错误的解决方法

17/06/27 14:34:41 info deprecation: mapred.map.tasks is deprecated. instead, use mapreduce.job.maps 
17/06/27 14:34:41 info memorystore: block broadcast_0 stored as values in memory (estimated size 788.8 kb, free 1246.5 mb) 
17/06/27 14:34:41 info memorystore: block broadcast_0_piece0 stored as bytes in memory (estimated size 54.0 kb, free 1246.4 mb) 
17/06/27 14:34:41 info blockmanagerinfo: added broadcast_0_piece0 in memory on 10.50.70.121:37335 (size: 54.0 kb, free: 1247.2 mb) 
17/06/27 14:34:41 info sparkcontext: created broadcast 0 from rdd at tradeinfooutlier.scala:30 
exception in thread "main" java.lang.nosuchmethoderror: scala.reflect.api.javauniverse.runtimemirror(ljava/lang/classloader;)lscala/reflect/api/javauniverse$javamirror; 
at com.fangdd.data.profile.outlier.tradeinfooutlier$.main(tradeinfooutlier.scala:30) 
at com.fangdd.data.profile.outlier.tradeinfooutlier.main(tradeinfooutlier.scala) 
at sun.reflect.nativemethodaccessorimpl.invoke0(native method) 
at sun.reflect.nativemethodaccessorimpl.invoke(nativemethodaccessorimpl.java:62) 
at sun.reflect.delegatingmethodaccessorimpl.invoke(delegatingmethodaccessorimpl.java:43) 
at java.lang.reflect.method.invoke(method.java:498) 
at org.apache.spark.deploy.sparksubmit$.org$apache$spark$deploy$sparksubmit$$runmain(sparksubmit.scala:745) 
at org.apache.spark.deploy.sparksubmit$.dorunmain$1(sparksubmit.scala:181) 
at org.apache.spark.deploy.sparksubmit$.submit(sparksubmit.scala:206) 
at org.apache.spark.deploy.sparksubmit$.main(sparksubmit.scala:121) 
at org.apache.spark.deploy.sparksubmit.main(sparksubmit.scala) 
17/06/27 14:34:42 info sparkcontext: invoking stop() from shutdown hook 

这种错误是由于生产环境采用的是scala 2.10 + spark1.6.3的运行环境,本地打的application jar使用scala2.11 + spark.1.6.3的编译环境,所以放入生产环境集群报了上述错误,更改scala版本重新打jar包后运行成功

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。