如何使用Cloudera CDH 5.8.0虚拟框解决Spark库冲突

时间:2016-12-16 10:55:02

标签: java maven apache-spark cloudera

我正在尝试提交一个工作来激发Cloudera CDH 5.8.0虚拟框,我正在使用json库,我也使用maven-shade插件来包含对jar文件的依赖,以下是我的pom:< / p>

<project>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>spark</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>

        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-core_2.11</artifactId>
            <version>1.5.1</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.json</groupId>
            <artifactId>json</artifactId>
            <version>20160810</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>2.3</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <filters>
                        <filter>
                            <artifact>*:*</artifact>
                            <excludes>
                                <exclude>META-INF/*.SF</exclude>
                                <exclude>META-INF/*.DSA</exclude>
                                <exclude>META-INF/*.RSA</exclude>
                            </excludes>
                        </filter>
                    </filters>
                    <finalName>uber-${project.artifactId}-${project.version}</finalName>
                </configuration>
            </plugin>
        </plugins>
    </build>


</project>

提交命令是:

spark-submit --class com.example.spark.SparkParser --master local[*] uber-spark-0.0.1-SNAPSHOT.jar 

我一直有以下异常:

Exception in thread "main" java.lang.NoSuchMethodError:
org.json.JSONTokener.<init>(Ljava/io/InputStream;)

我找到了一个小代码,可以告诉哪个库加载了类:

ClassLoader classloader = org.json.JSONTokener.class.getClassLoader();
URL res = classloader.getResource("org/json/JSONTokener.class");
String path = res.getPath();
System.out.println("Core JSONTokener came from " + path);

输出如下:

Core JSONTokener came from file:/usr/lib/hive/lib/hive-exec-1.1.0-cdh5.8.0.jar!/org/json/JSONTokener.class

我可以在CDH的虚拟框中本地找到该文件,如下所示:

[cloudera@quickstart ~]$ ls -l /usr/lib/hive/lib/hive-exec-1.1.0-cdh5.8.0.jar
-rw-r--r-- 1 root root 19306194 Jun 16  2016 /usr/lib/hive/lib/hive-exec-1.1.0-cdh5.8.0.jar

我甚至尝试将json库设为&#39;提供&#39;从我的jar文件中排除它,但仍然是相同的错误。

我试图删除名为的本地jar文件: /usr/lib/hive/lib/hive-exec-1.1.0-cdh5.8.0.jar 我的代码工作正常,但我不确定这是正确的解决方案,如果删除这个库会以某种方式伤害cloudera。

那么,我怎么能告诉spark不要使用这个本地jar文件,并使用我的&#39; uber-spark-0.0.1-SNAPSHOT.jar&#39;中包含的文件。档案?

1 个答案:

答案 0 :(得分:1)

不确定为什么之前没有人回答你...

您的问题是您在运行时类路径中有两个不同版本的同一个库。一个包含在你的罐子里,另一个由Cloudera添加。在JSONTokener中有一个方法在两个版本之间是不同的(可能它在一个版本上不存在或签名已经更改),您在代码中使用一个版本(这就是您的代码编译的原因)但在运行时期间ClassLoader正在使用另一个。

您的问题的简短答案是您不能:Java ClassLoader加载路径中的所有库,当您加载类时,它会加载它找到的第一个库。在这种情况下,由Hive运行时提供的那个。

更长的回答: 强制使用应用程序附带的jar的唯一选择是编辑spark默认值,使其不包含Hive。现在,我不完全确定如何在你的情况下这样做,但我可能会查看/etc/spark/spark-defaults.conf,尝试禁用Hive或Cloudera Manager内部的某些东西是要走的路

更好的选择是从项目中删除jar,将Cloudera Maven存储库添加到pom中并将hive-exec-1.1.0-cdh5.8.0作为提供的依赖项包含在内,有关详细信息,请参阅Using the CDH 5 Maven repository有关如何执行此操作的信息。

希望这有帮助。