我一直在一个本地集群上运行我的Spark作业,该集群具有读取输入的hdfs并且输出也被写入。现在我已经设置了一个AWS EMR和一个S3存储桶,我有输入,我也想将输出写入S3。
错误:
用户类抛出异常:java.lang.IllegalArgumentException:错误 FS:s3://某事/输入,预期: HDFS://ip-some-numbers.eu-west-1.compute.internal:8020
我尝试搜索相同的问题,并且有几个关于此问题的问题。有人建议它只用于输出,但即使我禁用输出,我也会得到同样的错误。
另一个建议是我的代码中FileSystem
出现了问题。以下是我的程序中输入/输出的所有内容:
第一次出现在我的自定义FileInputFormat
中,在getSplits(JobContext job)
中,我实际上没有修改过自己,但我可以:
FileSystem fs = path.getFileSystem(job.getConfiguration());
我的自定义RecordReader
中的类似案例,也没有修改过我自己:
final FileSystem fs = file.getFileSystem(job);
我自己撰写的自定义nextKeyValue()
的{{1}}我使用:
RecordReader
最后当我想检测我使用的文件夹中的文件数时:
FileSystem fs = FileSystem.get(jc);
我认为问题出在我的代码上,但如何修改val fs = FileSystem.get(sc.hadoopConfiguration)
val status = fs.listStatus(new Path(path))
调用以支持S3的输入/输出?
答案 0 :(得分:1)
hadoop文件系统apis不支持开箱即用的S3。 S3的hadoop文件系统apis有两种实现:S3A和S3N。 S3A似乎是首选实现。要使用它,你必须做一些事情:
在FileSystem的配置中创建FileSystem包含以下属性的值时:
fs.s3a.access.key
fs.s3a.secret.key
s3://
使用s3a://
。注意:创建一个简单的用户并首先使用基本身份验证进行尝试。可以使用AWS的更高级的临时凭证机制,但它有点涉及,我不得不对FileSystem代码进行一些更改,以便在我尝试时使其工作。
信息来源为here
答案 1 :(得分:0)
这是我在EMR上启动火花作业时要解决的问题:
val hdfs = FileSystem.get(new java.net.URI(s"s3a://${s3_bucket}"), sparkSession.sparkContext.hadoopConfiguration)
请确保将s3_bucket替换为您的存储桶的名称
我希望它将对某人有所帮助
答案 2 :(得分:0)
尝试为文件系统设置默认URI:
rtServer (
id: 'Artifactory-1',
url: 'https://my-url.com/artifactory',
username: uname,
password: pwd
)
rtDownload (
serverId: 'Artifactory-1',
spec: '''{
"files": [{
"pattern": "my-repo/my-image/my-version/*",
"target": "tmp/",
"props": "status=pushed"
}]
}'''
)
//Then add some logic to check that tmp/my-image/my-version isn't empty
sh "ls -al tmp/my-image/my-version"
使用
指定密钥和机密后FileSystem.setDefaultUri(spark.sparkContext.hadoopConfiguration, new URI(s"s3a://$s3bucket"))
并按照说明获取文件系统:
fs.s3a.access.key
fs.s3a.secret.key
我仍然会收到错误消息
val hdfs = FileSystem.get(new java.net.URI(s"s3a://${s3_bucket}"), sparkSession.sparkContext.hadoopConfiguration)
要检查默认文件系统,可以查看上面创建的hdfs FileSystem:
java.lang.IllegalArgumentException: Wrong FS: s3a:// ... , expected: file:///
对我来说仍然返回hadoopfs.getUri
为了使其正常工作,请在运行file:///
之前 ,设置文件系统的默认URI。
FileSystem.get
答案 3 :(得分:0)
EMR 配置为避免在代码或作业配置中使用密钥。 问题在于文件系统是如何创建的。
Hadoop 创建的默认文件系统是用于 hdfs 架构的文件系统。
因此,如果 path
架构为 s3://
,则下一段代码将不起作用。
val fs = FileSystem.get(sc.hadoopConfiguration)
val status = fs.listStatus(new Path(path))
要创建正确的文件系统,您需要将路径与您将使用的架构一起使用。例如,像这样:
val conf = sc.hadoopConfiguration
val pObj = new Path(path)
val status = pObj.getFileSystem(conf).listStatus(pObj)
来自 Hadoop 代码:
在 FileSystem.get 中实现
public static FileSystem get(Configuration conf) throws IOException {
return get(getDefaultUri(conf), conf);
}
使用 Path.getFileSystem 实现:
public FileSystem getFileSystem(Configuration conf) throws IOException {
return FileSystem.get(this.toUri(), conf);
}