Spark Slave中NettyChannelBuilder类未找到错误及依赖冲突解决
问题说明
在Spark 2.4.6 Slave节点运行基于Guava 29.0-jre构建的JAR包时,出现如下错误:
Exception occurred while create new JwtSource
java.lang.NoClassDefFoundError: Could not initialize class io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder
at io.spiffe.workloadapi.internal.GrpcManagedChannelFactory.createNativeSocketChannel(GrpcManagedChannelFactory.java:55)
at io.spiffe.workloadapi.internal.GrpcManagedChannelFactory.newChannel(GrpcManagedChannelFactory.java:41)
at io.spiffe.workloadapi.DefaultWorkloadApiClient.newClient(DefaultWorkloadApiClient.java:133)
at io.spiffe.workloadapi.DefaultJwtSource.createClient(DefaultJwtSource.java:221)
at io.spiffe.workloadapi.DefaultJwtSource.newSource(DefaultJwtSource.java:90)
根源是Spark自带的/opt/spark-2.4.6-bin-hadoop2.7/jars/guava-14.0.jar与自定义JAR依赖的高版本Guava存在冲突。
解决方案
1. 提交任务时强制优先加载用户依赖
提交任务时,通过--jars携带高版本Guava包,同时开启用户类路径优先配置:
spark-submit \ --class com.your.package.MainClass \ --jars /path/to/guava-29.0-jre.jar \ --conf spark.driver.userClassPathFirst=true \ --conf spark.executor.userClassPathFirst=true \ your-application.jar
注意:开启该配置可能引发Spark自身组件的依赖问题,需充分测试验证。
2. 替换Spark集群自带的低版本Guava
直接替换Spark安装目录中的Guava包,全局生效:
- 备份原文件:
mv /opt/spark-2.4.6-bin-hadoop2.7/jars/guava-14.0.jar /opt/spark-2.4.6-bin-hadoop2.7/jars/guava-14.0.jar.bak - 复制高版本Guava到Spark jars目录:
cp /path/to/guava-29.0-jre.jar /opt/spark-2.4.6-bin-hadoop2.7/jars/ - 重启Spark集群,确保所有Slave节点完成替换。
注意:此方法会影响集群上所有任务,需确认高版本Guava与Spark其他组件兼容。
3. 构建JAR时通过Shade插件隔离Guava包
使用Maven Shade或Gradle Shadow插件,将自定义JAR中的Guava包路径重命名,完全避免冲突:
Maven Shade插件配置示例
在项目pom.xml中添加如下插件配置:
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.3.0</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <relocations> <relocation> <pattern>com.google.common</pattern> <shadedPattern>com.your.package.shaded.google.common</shadedPattern> </relocation> </relocations> </configuration> </execution> </executions> </plugin> </plugins> </build>
执行mvn package后,生成的shaded JAR会将Guava包重命名,与Spark的Guava彻底隔离。
4. 配置额外类路径优先加载高版本Guava
通过extraClassPath配置将高版本Guava添加到类路径最前端:
spark-submit \ --class com.your.package.MainClass \ --conf spark.driver.extraClassPath=/path/to/guava-29.0-jre.jar \ --conf spark.executor.extraClassPath=/path/to/guava-29.0-jre.jar \ your-application.jar
注意:需确保Guava包路径在所有Slave节点可访问,可将包上传至HDFS,路径改为hdfs:///path/to/guava-29.0-jre.jar。
内容的提问来源于stack exchange,提问作者anand

