You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用spark-submit运行Spring Boot应用时遭遇ClassNotFoundException问题排查

问题原因分析与解决方案

这个ClassNotFoundException本质上是Spark在YARN Cluster模式下无法找到Spring Boot的核心类,主要有两个关键原因:

1. Spring Boot可执行Jar的结构与Spark ClassLoader不兼容

你用Spring Boot默认插件打包出来的Jar是可执行Jar,它的依赖包都放在BOOT-INF/lib目录下,而Spark的ClassLoader在Cluster模式下并不会自动扫描这个路径下的类,导致Spring Boot的核心类(比如SpringApplication)无法被加载。

2. Cluster模式下的依赖分发问题

yarn-cluster模式中,Driver进程是在YARN集群的某个节点上启动的,而不是本地机器。如果你的Jar是"瘦Jar"(只包含自己的代码,依赖在本地),集群节点上没有这些依赖,自然会找不到类。即使你本地有依赖,Spark也不会自动把本地依赖上传到集群。


解决办法

方法一:用Maven Shade插件打包成标准Fat Jar

修改你的pom.xml,添加maven-shade-plugin,它会把所有依赖(包括Spring Boot的核心库)合并到一个Jar中,并且生成Spark能识别的Classpath结构:

<build>
    <plugins>
        <!-- 跳过Spring Boot默认的可执行Jar生成,改用Shade插件打包 -->
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <skip>true</skip>
            </configuration>
        </plugin>
        <!-- 添加Shade插件 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.2.4</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <transformers>
                            <!-- 指定主类入口 -->
                            <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <mainClass>sample.dummy</mainClass>
                            </transformer>
                            <!-- 处理Spring Boot的资源文件冲突 -->
                            <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                <resource>META-INF/spring.handlers</resource>
                            </transformer>
                            <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                <resource>META-INF/spring.schemas</resource>
                            </transformer>
                        </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

执行mvn clean package后,会生成一个包含所有依赖的Fat Jar,用这个Jar重新执行spark-submit命令即可。

方法二:在spark-submit中显式指定依赖Jar(不推荐)

如果你不想修改打包方式,可以把Spring Boot相关的依赖Jar收集到集群可访问的路径(比如HDFS),然后在spark-submit中用--jars参数指定这些Jar:

./spark-submit \
--class sample.dummy \
--master yarn-cluster \
--driver-memory 5G \
--deploy-mode cluster \
--executor-memory 7G \
--executor-cores 1 \
--num-executors 1 \
--conf spark.yarn.executor.memoryOverhead=1024 \
--jars hdfs:///path/to/spring-boot-starter.jar,hdfs:///path/to/other-dependencies.jar \
/hadoop/app/abc/bootup/sample-0.0.1-SNAPSHOT.jar \
--runner=SparkRunner

这种方式需要手动管理所有依赖,容易遗漏,所以更推荐第一种方法。


内容的提问来源于stack exchange,提问作者Pratik Joshi

火山引擎 最新活动