Apache Spark 3.1.2使用spark-hadoop-cloud无法读取S3问题咨询
问题根因
该报错是Guava版本冲突导致的:Apache Spark 3.1.x内置依赖的Guava版本为14.0/16.0,而Cloudera发行版的spark-hadoop-cloud、hadoop-aws组件依赖高版本Guava,高版本新增的com.google.common.base.Preconditions.checkArgument多参数重载方法在Spark内置的低版本Guava中不存在,类加载时优先加载了Spark自带的低版本Guava,就会抛出该方法不存在异常。
解决方案
不要使用Cloudera定制版本的spark-hadoop-cloud组件,原生Apache Spark 3.1.2可以通过官方标准依赖组合实现S3读写,无需额外引入第三方发行版组件,操作步骤如下:
- 第一步:移除现有依赖中所有Cloudera来源的包,以及不必要的spark-hadoop-cloud依赖,调整sbt配置如下:
version := "0.0.1" scalaVersion := "2.12.12" lazy val app = (project in file("app")).settings( assemblyPackageScala / assembleArtifact := false, assembly / assemblyJarName := "uber.jar", assembly / mainClass := Some("com.example.Main"), // 核心:打包时排除Spark自带的低版本Guava,强制使用兼容版本的Guava assembly / assemblyExcludedJars := { val cp = (assembly / fullClasspath).value cp filter {_.data.getName.startsWith("guava-")} }, // 解决冲突时优先使用高版本类 assembly / assemblyMergeStrategy := { case PathList("META-INF", xs @ _*) => MergeStrategy.discard case x => MergeStrategy.first } ) libraryDependencies += "org.apache.spark" %% "spark-core" % "3.1.2" % "provided" libraryDependencies += "org.apache.spark" %% "spark-sql" % "3.1.2" % "provided" // 匹配Spark 3.1.2内置的Hadoop 3.2.0版本引入对应hadoop-aws libraryDependencies += "org.apache.hadoop" % "hadoop-aws" % "3.2.0" // 引入hadoop-aws 3.2.0匹配的aws-java-sdk-bundle版本 libraryDependencies += "com.amazonaws" % "aws-java-sdk-bundle" % "1.11.375" // 引入和高版本Hadoop兼容的Guava,避免方法不存在 libraryDependencies += "com.google.guava" % "guava" % "27.0-jre" libraryDependencies += "com.github.mrpowers" %% "spark-daria" % "0.38.2" libraryDependencies += "com.github.mrpowers" %% "spark-fast-tests" % "0.21.3" % "test" libraryDependencies += "org.scalatest" %% "scalatest" % "3.0.1" % "test"
- 第二步:调整Spark会话配置,添加S3A相关参数:
import org.apache.spark.sql.SparkSession object SparkApp { def main(args: Array[String]){ val spark = SparkSession.builder().master("local") .appName("spark session") // S3访问密钥配置,生产环境建议通过环境变量/IAM角色传递,避免硬编码 .config("spark.hadoop.fs.s3a.access.key", "你的访问密钥AK") .config("spark.hadoop.fs.s3a.secret.key", "你的访问密钥SK") // S3A实现类配置 .config("spark.hadoop.fs.s3a.impl", "org.apache.hadoop.fs.s3a.S3AFileSystem") // 路径风格访问开关,可根据你使用的S3服务配置调整 .config("spark.hadoop.fs.s3a.path.style.access", "true") .getOrCreate val jsonDF = spark.read.json("s3a://path-to-bucket/compact.json") val csvDF = spark.read.format("csv").load("s3a://path-to-bucket/some.csv") jsonDF.show() csvDF.show() } }
- 第三步:如果是提交到Spark集群运行,作业提交时添加参数强制优先加载用户包中的类:
spark-submit \ --conf spark.driver.userClassPathFirst=true \ --conf spark.executor.userClassPathFirst=true \ --class com.example.Main \ uber.jar
验证
调整后重新打包运行,即可正常读写S3存储,不会再出现Guava方法不存在的异常。
内容的提问来源于stack exchange,提问作者discord
相关产品推荐
相关产品推荐

