从Spark 2.0访问S3

7

我正在尝试从SparkSQL作业中访问S3文件。我已经尝试了几篇文章中提供的解决方案,但似乎都没有起作用。可能是因为我的EC2集群运行了适用于Hadoop2.7的新版Spark2.0。

我是这样设置hadoop的:

sc.hadoopConfiguration.set("fs.s3a.impl","org.apache.hadoop.fs.s3a.S3AFileSystem")
sc.hadoopConfiguration.set("fs.s3a.awsAccessKeyId", accessKey)
sc.hadoopConfiguration.set("fs.s3a.awsSecretAccessKey", secretKey)

我使用sbt assembly构建了一个超级JAR,命令如下:

name := "test"
version := "0.2.0"
scalaVersion := "2.11.8"

libraryDependencies += "com.amazonaws" % "aws-java-sdk" %   "1.7.4"
libraryDependencies += "org.apache.hadoop" % "hadoop-aws" % "2.7.3" excludeAll(
    ExclusionRule("com.amazonaws", "aws-java-sdk"),
    ExclusionRule("commons-beanutils")
)

libraryDependencies += "org.apache.spark" %% "spark-core" % "2.0.0" % "provided"
libraryDependencies += "org.apache.spark" %% "spark-sql" % "2.0.0" % "provided"

当我将作业提交到集群时,总是会出现以下错误:
异常线程“main”org.apache.spark.SparkException:由于阶段失败而中止作业:阶段0.0中的任务0失败了4次,最新的故障:在阶段0.0中丢失了任务0.3(TID 6,172.31.7.246):java.lang.RuntimeException:java.lang.ClassNotFoundException:未找到类org.apache.hadoop.fs.s3a.S3AFileSystem 在org.apache.hadoop.conf.Configuration.getClass(Configuration.java:2195)处 在org.apache.hadoop.fs.FileSystem.getFileSystemClass(FileSystem.java:2638)处 在org.apache.hadoop.fs.FileSystem.createFileSystem(FileSystem.java:2651)处 在org.apache.hadoop.fs.FileSystem.access $ 200(FileSystem.java:92)时 在org.apache.hadoop.fs.FileSystem $ Cache.getInternal(FileSystem.java:2687)处 在org.apache.hadoop.fs.FileSystem $ Cache.get(FileSystem.java:2669)处 在org.apache.hadoop.fs.FileSystem.get(FileSystem.java:371)时 在org.apache.spark.util.Utils $ .getHadoopFileSystem(Utils.scala:1726)时 在org.apache.spark.util.Utils $ .doFetchFile(Utils.scala:662)时 在org.apache.spark.util.Utils $ .fetchFile(Utils.scala:446)时 在org.apache.spark.executor.Executor $$ anonfun $ org $ apache $ spark $ executor $ Executor $$ updateDependencies $ 3.apply(Executor.scala:476)
看起来驱动程序可以从S3读取,但是工作者/执行程序不能...我不明白为什么我的uberjar不足够。
然而,我也尝试了以下配置spark-submit,但没有成功:
--packages com.amazonaws:aws-java-sdk:1.7.4,org.apache.hadoop:hadoop-aws:2.7.3
PS:如果我切换到s3n协议,则会出现以下异常:
java.io.IOException:方案没有文件系统:s3n

你是否在任何转换或操作中使用过访问S3文件? - Sandeep Purohit
是的,我在map和reduce操作中调用本地C函数(通过JNI)。实际上,包含这些函数的库已经上传到S3存储桶中,并且需要在运行本地函数之前由每个工作节点加载。因此,我使用sc.addFile(s3://pathToLibrary.so)将库添加到Spark上下文中,然后使用System.load(SparkFiles.get(Library.so))进行加载。 - elldekaa
你可以将aws-sdk和hadoop-aws复制到spark内的jars文件夹中(这应该可以解决ClassNotFoundException问题)。 - rdllopes
2个回答

8
如果您想使用 s3n
sc.hadoopConfiguration.set("fs.s3n.impl","org.apache.hadoop.fs.s3native.NativeS3FileSystem")
sc.hadoopConfiguration.set("fs.s3n.awsAccessKeyId", accessKey)
sc.hadoopConfiguration.set("fs.s3n.awsSecretAccessKey", secretKey)

关于异常,您需要确保两个 JAR 文件在 driverworker 的类路径上,并且如果您使用客户端模式通过 --jars 标志分发到 worker 节点,请确保它们也被分发:

spark-submit \
--conf "spark.driver.extraClassPath=/location/to/aws-java-sdk.jar" \
--conf "spark.driver.extraClassPath=/location/to/hadoop-aws.jar" \
--jars /location/to/aws-java-sdk.jar,/location/to/hadoop-aws.jar \

另外,如果您正在构建 uber JAR 并包含 aws-java-sdkhadoop-aws,则没有理由使用 --packages 标志。


我已经尝试了相同的s3n协议参数,但没有成功(如果我没有解释清楚,对不起)。 我知道如果我已经在uber JAR中有依赖项,那么--packages是不需要的。我尝试了这两种方法,但都没有成功。 我将尝试手动分发JAR文件,并将它们添加到类路径和JAR配置中,以查看是否仍然会出现异常。 - elldekaa
@elldekka,你的命名空间搞对了吗?使用NativeS3FileSystem了吗? - Yuval Itzchakov
是的,我做了,问题不是来自这部分。 - elldekaa
@elldekka 你确定类路径设置正确了吗? - Yuval Itzchakov
不,我改变了做法(请参考其他答案)... 我不明白为什么在运行uberjar时需要设置任何类路径... - elldekaa
导致找不到指定的文件系统。 - oneirois

1
实际上,Spark 的所有操作都在工作节点上执行。您可以在主节点上设置这些配置,因此一旦您尝试在 mapPartition 上应用 S3 的应用程序配置,就可以了。

好的,你是对的,我通过先将S3文件复制到本地,然后再将其添加到SparkFiles中来解决了这个问题。 - elldekaa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接