IllegalArgumentException,从s3而不是hdfs指定输入/输出时错误的FS

时间:2018-01-25 10:27:47

标签: amazon-web-services amazon-s3 filesystems hdfs

我一直在一个本地集群上运行我的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的输入/输出?

4 个答案:

答案 0 :(得分:1)

hadoop文件系统apis不支持开箱即用的S3。 S3的hadoop文件系统apis有两种实现:S3A和S3N。 S3A似乎是首选实现。要使用它,你必须做一些事情:

  1. 将aws-java-sdk-bundle.jar添加到类路径中。
  2. 在FileSystem的配置中创建FileSystem包含以下属性的值时:

    fs.s3a.access.key
    fs.s3a.secret.key
    
  3. 在S3上指定路径时,请不要使用s3://使用s3a://
  4. 注意:创建一个简单的用户并首先使用基本身份验证进行尝试。可以使用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);
   }