Scala 2.13下Spark应用sbt run成功但spark-submit报NoSuchMethodError
问题原因与解决办法
核心原因:Scala版本不兼容+依赖打包冲突
Scala 2.12和2.13的字节码不兼容,Spark针对不同Scala版本发布了独立构件(如spark-sql_2.12和spark-sql_2.13)。你遇到的NoSuchMethodError本质是:
- 本地
sbt run会严格使用你指定的Scala 2.13对应的Spark依赖,所以运行正常;但spark-submit会优先加载集群环境中的Spark依赖,若集群Spark是基于Scala 2.12编译的,或你的应用jar中混入了Scala 2.12版本的Spark类,就会出现方法找不到的错误——因为Spark在两个Scala版本中,SparkSession$implicits的方法字节码结构存在差异。
解决办法
1. 确认集群Spark的Scala版本
先检查集群上Spark的Scala编译版本,执行:
spark-shell --version
查看输出里的Scala version字段。如果是2.12,要么把项目切回Scala 2.12,要么升级集群Spark到基于Scala 2.13的发行版(Spark 3.2+官方支持2.13,但需确保集群安装的是对应版本的Spark包)。
2. 修正SBT配置,对齐Scala与Spark依赖版本
在build.sbt中明确指定Scala版本,并用%%自动匹配Spark依赖的Scala后缀:
scalaVersion := "2.13.10" // 选Spark 3.3.2兼容的2.13子版本 libraryDependencies ++= Seq( "org.apache.spark" %% "spark-sql" % "3.3.2" % Provided, // 其他依赖也用%%,避免手动指定错误的Scala版本后缀 )
%%会自动给依赖名加上_2.13后缀,确保拉取的是Scala 2.13版本的Spark构件。
3. 标记Spark核心依赖为Provided
将spark-core、spark-sql等核心依赖标记为Provided,这样打包时不会把它们打进应用jar,避免和集群上的Spark依赖冲突:
- 如上配置中的
% Provided,告诉SBT这些依赖由集群运行环境提供,无需打包。
4. 重新打包并验证依赖正确性
执行sbt clean package重新构建,然后检查jar包中的依赖版本:
unzip -l target/scala-2.13/your-app.jar | grep "spark-sql"
如果输出里出现_2.12,说明依赖仍未对齐,需回到SBT配置排查。
5. 提交时强制指定Scala 2.13的Spark依赖(可选)
若集群同时存在多版本Spark,提交时可通过配置指定使用Scala 2.13的Spark依赖:
spark-submit --conf spark.driver.extraClassPath=/path/to/spark-3.3.2-scala-2.13/jars/* \ --conf spark.executor.extraClassPath=/path/to/spark-3.3.2-scala-2.13/jars/* \ target/scala-2.13/your-app.jar
内容的提问来源于stack exchange,提问作者Hongbo Miao
相关产品推荐
相关产品推荐

