httpclient版本与Apache Spark之间的冲突

时间:2016-06-15 18:43:56

标签: java apache-spark amazon-ec2 apache-httpclient-4.x

我正在使用Apache Spark开发Java应用程序。我用这个版本:

<dependency>
    <groupId>org.apache.spark</groupId>
    <artifactId>spark-core_2.10</artifactId>
    <version>1.2.2</version>
</dependency>

在我的代码中,有一个过渡依赖:

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.2</version>
</dependency>

我将我的应用程序打包到一个JAR文件中。使用spark-submit在EC2实例上部署它时,我收到此错误。

Caused by: java.lang.NoSuchFieldError: INSTANCE
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.<clinit>(SSLConnectionSocketFactory.java:144)
    at com.amazonaws.http.apache.client.impl.ApacheConnectionManagerFactory.getPreferredSocketFactory(ApacheConnectionManagerFactory.java:87)
    at com.amazonaws.http.apache.client.impl.ApacheConnectionManagerFactory.create(ApacheConnectionManagerFactory.java:65)
    at com.amazonaws.http.apache.client.impl.ApacheConnectionManagerFactory.create(ApacheConnectionManagerFactory.java:58)
    at com.amazonaws.http.apache.client.impl.ApacheHttpClientFactory.create(ApacheHttpClientFactory.java:50)
    at com.amazonaws.http.apache.client.impl.ApacheHttpClientFactory.create(ApacheHttpClientFactory.java:38)

此错误清楚地表明SparkSubmit已加载相同Apache httpclient库的旧版本,因此发生此冲突。

解决此问题的好方法是什么?

出于某种原因,我不能在我的Java代码上升级Spark。但是,我可以轻松地使用EC2群集。是否可以在具有更高版本的集群上部署我的java代码,例如1.6.1版本?

1 个答案:

答案 0 :(得分:7)

正如你在帖子中所说,Spark正在加载httpclient的旧版本。解决方案是使用Maven的relocation工具来制作一个整洁的无冲突项目。

以下是如何在pom.xml文件中使用它的示例:

<project>
  <!-- Your project definition here, with the groupId, artifactId, and it's dependencies --> 
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>2.4.3</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>shade</goal>
            </goals>
            <configuration>
              <relocations>
                <relocation>
                  <pattern>org.apache.http.client</pattern>
                  <shadedPattern>shaded.org.apache.http.client</shadedPattern>
                </relocation>
              </relocations>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

</project>

这会将所有文件从org.apache.http.client移至shaded.org.apache.http.client,从而解决冲突。

原帖:

如果这只是传递依赖的问题,您可以将其添加到spark-core依赖项中以排除Spark使用的HttpClient:

<dependency>
    <groupId>org.apache.spark</groupId>
    <artifactId>spark-core_2.10</artifactId>
    <version>1.2.2</version>
    <scope>provided</scope>
    <exclusions>
        <exclusion>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
        </exclusion>
    </exclusions>
</dependency>

我还在您的依赖项中添加了scope作为provided,因为它将由您的群集提供。

然而,这可能会破坏Spark的内部行为。如果在执行此操作后仍然出现错误,您可以尝试使用Maven的relocation工具,该工具可以产生一个整洁的无冲突项目。

关于您无法升级Spark版本的事实,您是否使用了mvnrepository中的this dependency声明?

Spark向后兼容,在具有更高版本的群集上部署作业不会有任何问题。