Apache Spark——使用 spark-submit 抛出 NoSuchMethodError

Apache Spark -- using spark-submit throws a NoSuchMethodError

要将 Spark 应用程序提交到集群,他们的文档说明:

To do this, create an assembly jar (or “uber” jar) containing your code and its dependencies. Both sbt and Maven have assembly plugins. When creating assembly jars, list Spark and Hadoop as provided dependencies; these need not be bundled since they are provided by the cluster manager at runtime. -- http://spark.apache.org/docs/latest/submitting-applications.html

因此,我将 Apache Maven Shade 插件添加到我的 pom.xml 文件中。 (版本 3.0.0)
我将我的 Spark 依赖项的范围变成了 provided。 (版本 2.1.0)

(我还添加了 Apache Maven Assembly 插件,以确保我在 运行 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;

抛出错误的代码行无关紧要——它只是我主要方法中创建 Stopwatch 的第一行,Google Guava 实用程序的一部分。 (版本 21.0)

网上的其他解决方案表明它与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 文件夹。在那里你可以看到你是否有包含替代版本的番石榴的罐子,它不支持 Stopwatch

中的方法 createStarted()

如果您查看 Spark 2.1.0 安装的 /jars 子目录,您可能会看到 guava-14.0.1.jar。根据您使用的 API for the Guava Stopwatch#createStarted methodcreateStarted 在 Guava 15.0 之前不存在。最有可能发生的情况是,Spark 进程类加载器在找到打包在您的 uberjar 中的 Guava 21.0 库之前先找到了 Spark 提供的 Guava 14.0.1 库。

一个可能的解决方案是使用 class-relocation feature provided by the Maven Shade plugin(您已经在使用它来构建您的 uberjar)。通过 "class relocation",Maven-Shade 在 uberjar 的打包过程中将 Guava 21.0 类(您的代码需要)从反映其现有包名称的 pattern 位置移动(例如 com.google.common.base) 到您在阴影配置中指定的任意 shadedPattern 位置(例如 myguava123.com.google.common.base)。

结果是新旧 Guava 库不再共享包名,避免了运行时冲突。

应用以上答案通过以下配置解决问题:

  <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>