Spark Java加载JSON文件报NoClassDefFoundError: FSBuilder问题咨询
Spark加载JSON文件时出现
NoClassDefFoundError: org/apache/hadoop/fs/FSBuilder问题排查 问题描述
我正在开发一个需要加载JSON文件的Spark Java应用,该应用可正常加载Avro文件,但调用sparksession.read().json(hdfs_path_of_file)加载JSON文件时,抛出如下异常:
java.lang.NoClassDefFoundError org/apache/hadoop/fs/FSBuilder
而调用sparksession.read().format(avro).load(hdfs_path_of_file)加载Avro文件可正常运行。
项目Maven依赖配置
<dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-common</artifactId> <version>3.0.0</version> <exclusions> <exclusion> <artifactId>slf4j-log4j12</artifactId> <groupId>org.slf4j</groupId> </exclusion> <exclusion> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> </exclusion> <exclusion> <groupId>org.mortbay.jetty</groupId> <artifactId>jetty</artifactId> </exclusion> <exclusion> <groupId>org.apache.commons</groupId> <artifactId>commons-compress</artifactId> </exclusion> <exclusion> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> </exclusion> <exclusion> <groupId>commons-net</groupId> <artifactId>commons-net</artifactId> </exclusion> <exclusion> <groupId>commons-cli</groupId> <artifactId>commons-cli</artifactId> </exclusion> <exclusion> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-mapper-asl</artifactId> </exclusion> <exclusion> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-webapp</artifactId> </exclusion> <exclusion> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> </exclusion> <exclusion> <groupId>log4j</groupId> <artifactId>log4j</artifactId> </exclusion> <exclusion> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> </exclusion> <exclusion> <groupId>com.fasterxml.woodstox</groupId> <artifactId>woodstox-core</artifactId> </exclusion> <exclusion> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-server</artifactId> </exclusion> <exclusion> <groupId>org.codehaus.woodstox</groupId> <artifactId>stax2-api</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-hdfs</artifactId> <version>3.0.0</version> <exclusions> <exclusion> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> </exclusion> <exclusion> <groupId>io.netty</groupId> <artifactId>netty</artifactId> </exclusion> <exclusion> <groupId>commons-cli</groupId> <artifactId>commons-cli</artifactId> </exclusion> <exclusion> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-hdfs-client</artifactId> </exclusion> <exclusion> <groupId>io.netty</groupId> <artifactId>netty</artifactId> </exclusion> <exclusion> <groupId>xerces</groupId> <artifactId>xercesImpl</artifactId> </exclusion> <exclusion> <groupId>org.mortbay.jetty</groupId> <artifactId>jetty</artifactId> </exclusion> <exclusion> <groupId>org.mortbay.jetty</groupId> <artifactId>jetty-util</artifactId> </exclusion> <exclusion> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-mapper-asl</artifactId> </exclusion> <exclusion> <groupId>log4j</groupId> <artifactId>log4j</artifactId> </exclusion> <exclusion> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-hdfs-client</artifactId> <version>3.0.0</version> <exclusions> <exclusion> <groupId>com.squareup.okhttp</groupId> <artifactId>okhttp</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-core_2.11</artifactId> <version>2.4.7.7.1.7.48-2</version> <exclusions> <exclusion> <groupId>com.squareup.okhttp</groupId> <artifactId>okhttp</artifactId> </exclusion> <exclusion> <artifactId>slf4j-log4j12</artifactId> <groupId>org.slf4j</groupId> </exclusion> <exclusion> <groupId>org.apache.commons</groupId> <artifactId>commons-compress</artifactId> </exclusion> <exclusion> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> </exclusion> <exclusion> <groupId>commons-cli</groupId> <artifactId>commons-cli</artifactId> </exclusion> <exclusion> <groupId>commons-net</groupId> <artifactId>commons-net</artifactId> </exclusion> <exclusion> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-mapper-asl</artifactId> </exclusion> <exclusion> <groupId>log4j</groupId> <artifactId>log4j</artifactId> </exclusion> <exclusion> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> </exclusion> <exclusion> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-hdfs-client</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-sql_2.11</artifactId> <version>2.4.7.7.1.7.48-2</version> <exclusions> <exclusion> <groupId>org.apache.spark</groupId> <artifactId>spark-core_2.11</artifactId> </exclusion> <exclusion> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-mapper-asl</artifactId> </exclusion> <exclusion> <groupId>org.codehaus.janino</groupId> <artifactId>commons-compiler</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-avro_2.11</artifactId> <version>2.4.7.7.1.7.48-2</version> </dependency> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-hive_2.11</artifactId> <version>2.4.7.7.1.7.48-2</version> <scope>provided</scope> <exclusions> <exclusion> <groupId>org.apache.hive</groupId> <artifactId>hive-exec</artifactId> </exclusion> </exclusions> </dependency>
疑问与解答
疑问1:已引入hadoop-common依赖,为何仍找不到FSBuilder?
- 版本不匹配:你使用的Spark版本是
2.4.7.7.1.7.48-2(属于厂商定制版本),默认适配Hadoop 2.x系列,但手动指定的Hadoop依赖是3.0.0版本。FSBuilder是Hadoop 3.x新增的接口,Spark 2.4.x的JSON读取逻辑依赖的Hadoop版本中没有这个接口,同时手动引入的Hadoop 3.0.0与Spark自带的Hadoop依赖冲突,导致类路径混乱。 - 依赖排除过度:在
spark-core中排除了hadoop-hdfs-client,在hadoop-hdfs中也排除了该依赖,而FSBuilder实际存在于hadoop-hdfs-client包中,这直接导致该类无法被加载。 - 运行环境类路径冲突:集群运行环境中可能存在旧版本Hadoop jar包,优先级高于你项目引入的版本,导致JVM加载了不含
FSBuilder的旧类。
疑问2:FSBuilder是接口,JVM类加载器应该可以加载接口,为何会出现该错误?
NoClassDefFoundError不是说JVM无法加载接口,而是运行时找不到该接口的定义,常见触发场景:
- 编译时依赖的Hadoop版本包含该接口,但运行时类路径中缺失对应的jar包;
- 编译与运行的依赖版本不一致,比如编译用Hadoop 3.0.0,运行时用Hadoop 2.x,旧版本无该接口;
- Spark类加载器隔离机制导致应用类加载器无法访问该接口;
- 多版本依赖冲突,类加载器加载了旧版本的Hadoop类,而旧版本不存在该接口。
解决方案
- 移除手动指定的Hadoop依赖:直接使用Spark依赖传递的Hadoop版本,厂商定制的Spark版本已经适配了对应Hadoop版本,手动指定会引发冲突。
- 清理不必要的依赖排除:删除
spark-core和hadoop-hdfs中对hadoop-hdfs-client的排除规则,确保包含FSBuilder的jar包被正确引入。 - 检查运行环境类路径:确保集群环境中没有旧版本Hadoop jar包干扰,或者通过
--jars参数明确指定项目依赖的Hadoop jar包优先级。
内容的提问来源于stack exchange,提问作者Prateek Gautam
相关产品推荐
相关产品推荐

