添加hadoop-aws依赖后Spark Metrics System Sink实例化错误求助
我之前在处理HDP环境搭配Spark本地写S3的场景时,遇到过几乎一模一样的问题——核心就是依赖版本不匹配和加载顺序优先级在搞事情。结合你的情况,给你梳理几个必须注意的点:
1. 必须对齐HDP自带的Hadoop版本
HDP 2.6.3内置的Hadoop版本是2.7.3,你引入的hadoop-aws依赖必须严格跟这个版本保持一致,绝对不能随便用其他版本。Spark 2.2本身依赖的Hadoop版本和HDP的有差异,混用直接会导致类不兼容,这也是你看到MetricsServlet实例化失败的根源之一。
在pom.xml里要精准指定版本,同时排除和Spark核心依赖冲突的组件:
<dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-aws</artifactId> <version>2.7.3</version> <exclusions> <!-- 排除会覆盖Spark依赖的Hadoop通用组件 --> <exclusion> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-common</artifactId> </exclusion> <exclusion> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-client</artifactId> </exclusion> </exclusions> </dependency>
2. 严格控制依赖声明顺序
你说把hadoop-aws放在Spark依赖上面会出现Spark类缺失,这是因为Maven的依赖解析逻辑是先声明的依赖优先加载。如果hadoop-aws带的Hadoop组件先被加载,就会覆盖Spark核心依赖里的同名类,导致Spark找不到自己需要的类。
正确的顺序必须是:先声明Spark的核心依赖,再放hadoop-aws及其他Hadoop相关依赖。比如:
<!-- 先放Spark核心依赖,确保这些类优先被加载 --> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-core_2.11</artifactId> <version>2.2.0</version> </dependency> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-sql_2.11</artifactId> <version>2.2.0</version> </dependency> <!-- 再放hadoop-aws,避免它的依赖覆盖Spark的类 --> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-aws</artifactId> <version>2.7.3</version> <exclusions> <exclusion> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-common</artifactId> </exclusion> <exclusion> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-client</artifactId> </exclusion> </exclusions> </dependency>
3. 修复MetricsServlet实例化错误的直接方案
除了依赖调整,你还可以在Spark配置里直接指定正确的Metrics Servlet类,或者禁用冲突的Sink来解决这个错误:
在初始化SparkSession的时候加上这些配置:
import org.apache.spark.SparkConf val conf = new SparkConf() .setAppName("S3WriteTest") .setMaster("local[*]") // 强制指定Spark自带的MetricsServlet类,避免被Hadoop的类覆盖 .set("spark.metrics.conf.*.sink.servlet.class", "org.apache.spark.metrics.sink.MetricsServlet")
4. 本地测试S3的额外配置
最后,本地运行时别忘了配置S3的访问凭证和文件系统实现类,不然写S3还是会失败:
// 配置S3访问信息 conf.set("spark.hadoop.fs.s3a.access.key", "你的访问密钥") conf.set("spark.hadoop.fs.s3a.secret.key", "你的秘密密钥") conf.set("spark.hadoop.fs.s3a.impl", "org.apache.hadoop.fs.s3a.S3AFileSystem")
另外,如果你用IntelliJ开发,建议去File -> Project Structure -> Libraries里检查一下,有没有重复引入的Hadoop或Spark依赖,把多余的冲突版本删掉,这样能避免很多隐性问题。
内容的提问来源于stack exchange,提问作者Eric Hanson

