要将Spark应用程序提交到集群,他们的文档说明:
为此,请创建包含代码及其依赖项的程序集jar(或“uber”jar)。 sbt和Maven都有汇编插件。在创建程序集jar时,将Spark和Hadoop列为提供的依赖项;这些不需要捆绑,因为它们是由集群管理器在运行时提供的。 - http://spark.apache.org/docs/latest/submitting-applications.html
所以,我在我的pom.xml
文件中添加了Apache Maven Shade插件。 (3.0.0版)
我把我的Spark依赖的范围变成了provided
。 (版本2.1.0)
(我还添加了Apache Maven Assembly Plugin,以确保在运行mvn clean package
时我将所有依赖项都包装在jar中。我不确定它是否真的有必要。)
因此spark-submit
失败了。它为我所依赖的依赖项抛出一个NoSuchMethodError
(请注意,代码在IntelliJ中编译时从本地实例工作,假设删除了provided
)。
Exception in thread "main" java.lang.NoSuchMethodError: com.google.common.base.Stopwatch.createStarted()Lcom/google/common/base/Stopwatch;
抛出错误的代码行是无关紧要的 - 它只是我的main方法中的第一行创建了一个Stopwatch
,它是Google Guava实用程序的一部分。 (版本21.0)
在线的其他解决方案表明它与Guava的版本冲突有关,但我对这些建议还没有任何运气。任何帮助将不胜感激,谢谢。
如果你看一下Spark 2.1.0安装的/jars
子目录,你可能会看到guava-14.0.1.jar
。根据你使用的API for the Guava Stopwatch#createStarted
method,createStarted
直到Guava 15.0才存在。最有可能发生的事情是Spark进程Classloader在找到包装在你的uberjar中的Guava 21.0库之前找到了Spark提供的Guava 14.0.1库。
一种可能的解决方案是使用class-relocation feature provided by the Maven Shade plugin(你已经用它来构建你的uberjar)。通过“类重定位”,Maven-Shade移动Guava 21.0类(您的代码需要)在包装uberjar期间从pattern
位置反映他们现有的包名(例如com.google.common.base
)到任意shadedPattern
位置,您在阴影配置(例如myguava123.com.google.common.base
)。
结果是较旧和较新的Guava库不再共享包名,从而避免了运行时冲突。
很可能你有依赖冲突,是的。
首先,您可以在构建jar时查看是否存在依赖冲突。一个快速的方法是直接查看你的jar,看看是否有Stopwatch.class文件,如果通过查看字节码,似乎方法createStarted就在那里。否则,您还可以列出依赖关系树并从那里开始工作:https://maven.apache.org/plugins/maven-dependency-plugin/examples/resolving-conflicts-using-the-dependency-tree.html
如果你的jar不是问题,那么由于你的spark安装和jar之间的冲突,你可能会遇到依赖性问题。查看spark安装的lib和jars文件夹。在那里你可以看到你是否有包含备用版本的番石榴的罐子,它不支持来自秒表的方法createStarted()
应用以上答案通过以下配置解决问题:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<relocations>
<relocation>
<pattern>com.google.common</pattern>
<shadedPattern>shade.com.google.common</shadedPattern>
</relocation>
<relocation>
<pattern>com.google.thirdparty.publicsuffix</pattern>
<shadedPattern>shade.com.google.thirdparty.publicsuffix</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>