问题:
提交spark任务,hive写ck,部分executor报错
:
其他不报错的executor均能写入ck
判断为httpclient包冲突,但maven tree显示本地并无冲突
尝试:
jar包打fatjar,无用;
使用–jar提交依赖包;无用;
并报错:
ERROR TransportRequestHandler: Error while invoking RpcHandler#receive() for one-way message.
: Could not find CoarseGrainedScheduler.
后参考以下文章,得到解决:
源:/ljhbjehp/p/
提交Spark作业遇到的NoSuchMethodError问题总结
测试应用说明
测试的Spark应用实现了同步hive表到kafka的功能。具体处理流程:
从 ETCD 获取 SQL 语句和 Kafka 配置信息
使用 SparkSQL 读取 Hive 数据表
把 Hive 数据表的数据写入 Kafka
应用使用etcd来存储程序所需配置,通过拉取etcd的kv配置,来初始化sql语句和kafka配置的参数。
提交方式及相应的问题
使用client模式,提交无依赖的jar包
提交命令
/usr/local/spark-2.3.0-bin-2.8.2/bin/spark-submit
–name hive2kafka
–master yarn
–deploy-mode client
–driver-cores 1
–driver-memory 2g
–num-executors 2
–executor-cores 1
–executor-memory 2g
–queue hive
–class .Hive2Kafka
/data0/jianhong1/demo-v25/target/demo-1.
应用运行失败,driver端报错:
Exception in thread “main” : io/etcd/jetcd/Client
at (:27)
at (:46)
at .(:60)
…
Caused by: :
at (:381)
at (:424)
at (:357)
从报错信息可以看出,driver端没有查找到etcd的某个类,即没有加载到etcd 的jar包。说明spark应用driver进程的classpath不包含etcd 的jar包。因此考虑打包fat jar,把etcd的jar包打入用户提交的jar。
使用client模式,提交包含依赖的jar包
提交命令
/usr/local/spark-2.3.0-bin-2.8.2/bin/spark-submit
–name hive2kafka
–master yarn
–deploy-mode client
–driver-cores 1
–driver-memory 2g
–num-executors 2
–executor-cores 1
–executor-memory 2g
–queue hive
–class .Hive2Kafka
/data0/jianhong1/demo-v25/target/demo-1.
应用运行失败,driver端报错:
Exception in thread “main” : (ZLjava/lang/String;CLjava/lang/Object;)V
at
K
e
y
.
v
a
l
i
d
a
t
e
N
a
m
e
(
M
e
t
a
d
a
t
a
.
j
a
v
a
:
742
)
a
t
i
o
.
g
r
p
c
.
M
e
t
a
d
a
t
a
(:742) at
Key.validateName(Metadata.java:742)atio.grpc.MetadataKey.(:750)
at
K
e
y
.
<
i
n
i
t
>
(
M
e
t
a
d
a
t
a
.
j
a
v
a
:
668
)
a
t
i
o
.
g
r
p
c
.
M
e
t
a
d
a
t
a
Key.<init>(:668) at
Key.<init>(Metadata.java:668)atio.grpc.MetadataAsciiKey.(:959)
at
A
s
c
i
i
K
e
y
.
<
i
n
i
t
>
(
M
e
t
a
d
a
t
a
.
j
a
v
a
:
954
)
a
t
i
o
.
g
r
p
c
.
M
e
t
a
d
a
t
a
AsciiKey.<init>(:954) at
AsciiKey.<init>(Metadata.java:954)atio.grpc.Metadata(:705)
at $(:701)
at .(:69)
at .(:37)
at (:401)
at (:28)
at (:46)
at .(:60)
…
从报错信息可以看出,应用没有找到guava包的Preconditions类的checkArgument方法 。说明程序找到了guava包的Preconditions类,但是这个类没有找到checkArgument的某个构造方法。这种问题一般是由于jar包冲突,即程序加载了低版本的jar包,但是程序需要调用高版本jar包的某个方法,而这个方法低版本中没有,就会出现上面的报错NoSuchMethodError。
因此考虑把程序中冲突的低版本guava包排除掉。通过检查程序pom文件的jar包依赖,明确添加适配etcd高版本的guava包,并把冲突的低版本的guava包排除掉。重新运行,发现依然出现上面的NoSuchMethodError报错。
因此猜测低版本的guava包不是由于程序代码引入的,而是由spark提交机的本地包引入的。通过检查spark提交机的本地包,查到引入了guava-14.0.,而程序中etcd依赖的guava包需要的版本为20+。说明应用使用了本地jar的低版本guava类,而没有使用fat-jar的高版本guava类。由此推测出,spark应用driver端的类加载优先级:本地jar > fat-jar。
使用client模式,提交包含依赖的jar包,并添加driver-class 类路径
提交命令
/usr/local/spark-2.3.0-bin-2.8.2/bin/spark-submit
–name hive2kafka
–master yarn
–deploy-mode client
–driver-class-path /data0/jianhong1/demo-v25/target/lib/guava-23.:/data0/jianhong1/demo-v25/target/lib/protobuf-java-3.5.
–driver-cores 1
–driver-memory 2g
–num-executors 2
–executor-cores 1
–executor-memory 2g
–queue hive
–class .Hive2Kafka
/data0/jianhong1/demo-v25/target/demo-1.
程序正常运行,不再出现NoSuchMethodError报错。由此推测出,spark应用driver端的类加载优先级:driver-class-path 配置 > 本地jar。
使用cluster模式,提交包含依赖的jar包
提交命令
/usr/local/spark-2.3.0-bin-2.8.2/bin/spark-submit
–name hive2kafka
–master yarn
–deploy-mode cluster
–driver-cores 1
–driver-memory 2g
–num-executors 2
–executor-cores 1
–executor-memory 2g
–queue hive
–class .Hive2Kafka
/data0/jianhong1/demo-v25/target/demo-1.
应用运行失败,报错信息:
diagnostics: User class threw exception: : (ZLjava/lang/String;CLjava/lang/Object;)V
at $(:742)
at $Key.<init>(:750)
at $Key.<init>(:668)
at $AsciiKey.<init>(:959)
at $AsciiKey.<init>(:954)
at $(:705)
at $(:701)
at .<clinit>(:69)
at .<init>(:37)
at (:401)
at (:28)
at (:46)
at .(:66)
...
从报错信息可以看出,应用找到了guava包的Preconditions类,但是在这个类中没有找到checkArgument的某个构造方法。
因此考虑在提交作业时明确指出etcd所依赖的高版本guava包。于是提交参数添加了 --jars hdfs:/user/jianhong1/jars/guava-23.,hdfs:/user/jianhong1/jars/protobuf-java-3.5. \,重新运行后依然报上面的错。说明 --jar 参数只是负责把jar包拷贝到运行作业的服务器上,但是没把指定的jar包加到类路径。
使用cluster模式,提交包含依赖的jar包,并添加driver 和executor 类路径。
提交命令
/usr/local/spark-2.3.0-bin-2.8.2/bin/spark-submit
–name hive2kafka
–master yarn
–deploy-mode cluster
–driver-cores 1
–driver-memory 2g
–num-executors 2
–executor-cores 1
–executor-memory 2g
–queue hive
–class .Hive2Kafka
–conf =guava-23.:protobuf-java-3.5.
–conf =guava-23.:protobuf-java-3.5.
–jars hdfs:/user/jianhong1/jars/guava-23.,hdfs:/user/jianhong1/jars/protobuf-java-3.5.
/data0/jianhong1/demo-v25/target/demo-1.
通过增加guava包的driver 和executor 类路径的配置后,应用成功运行!
总结
本文介绍了client 方式和cluster 方式提交Spark 应用时所遇到的NoSuchMethodError 问题,及相应的解决方案。通过实际测试得到结论: spark应用的类加载优先级:–driver-class-path 或–executor-class-path配置 > 本地jar > fat-jar。
参考
/questions/37132559/add-jars-to-a-spark-job-spark-submit
The --jars argument only transports the jars to each machine in the cluster. It does NOT tell spark to use them in the class path search. The --driver-class-path (or similar arguments or config parameters) are also required.
–jars 参数只是用于传输 jar 包到集群的 Executor 和 Driver 的服务器上,它不会告知 spark 应用在哪个类路径下使用这些jar包。因此,–driver-class-path或–executor-class-path参数也是必需的,用于配置 driver 和 executor 的类路径。
Spark on Yarn运行时加载的jar包 /upupfeng/p/
spark on yarn运行时会加载的jar包有如下:
spark-submit中指定的–jars
$SPARK_HOME/jars下的jar包
yarn提供的jar包
spark-submit通过参数/指定的jar包
/docs/latest/ 官网文档