首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >无法从HDFS复制到S3A

无法从HDFS复制到S3A
EN

Stack Overflow用户
提问于 2019-08-19 10:38:17
回答 2查看 325关注 0票数 0

我有一个类可以使用Apache FileUtil将目录内容从一个位置复制到另一个位置。

代码语言:javascript
复制
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.FileUtil;
import org.apache.hadoop.fs.LocatedFileStatus;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.RemoteIterator;

class Folder {
    private final FileSystem fs;
    private final Path pth;

    // ... constructors and other methods

    /**
     * Copy contents (files and files in subfolders) to another folder.
     * Merges overlapping folders
     * Overwrites already existing files
     * @param destination Folder where content will be moved to
     * @throws IOException If fails
     */
    public void copyFilesTo(final Folder destination) throws IOException {
        final RemoteIterator<LocatedFileStatus> iter = this.fs.listFiles(
            this.pth,
            true
        );
        final URI root = this.pth.toUri();
        while (iter.hasNext()) {
            final Path source = iter.next().getPath();
            FileUtil.copy(
                this.fs,
                source,
                destination.fs,
                new Path(
                    destination.pth,
                    root.relativize(source.toUri()).toString()
                ),
                false,
                true,
                this.fs.getConf()
            );
        }
    }
}

这个类可以很好地处理单元测试中的本地(file:///)目录,但是当我试图在Hadoop集群中使用它将文件从HDFS (hdfs:///tmp/result)复制到AmazonS3 (s3a://mybucket/out)时,它不会复制任何东西,也不会抛出错误,只是默默地跳过复制。

当我将同一个类(包括HDFS或S3a文件系统)用于另一个目的时,它可以正常工作,因此配置和fs引用在这里应该是可以的。

我做错什么了?如何正确地将文件从HDFS复制到S3A?

我在用Hadoop 2.7.3

UPDATE I向copyFilesTo方法添加了更多日志,以记录rootsourcetarget变量(并提取rebase()方法而不更改代码):

代码语言:javascript
复制
    /**
     * Copy contents (files and files in subfolders) to another folder.
     * Merges overlapping folders
     * Overwrites already existing files
     * @param dst Folder where content will be moved to
     * @throws IOException If fails
     */
    public void copyFilesTo(final Folder dst) throws IOException {
        Logger.info(
            this, "copyFilesTo(%s): from %s fs=%s",
            dst, this, this.hdfs
        );
        final RemoteIterator<LocatedFileStatus> iter = this.hdfs.listFiles(
            this.pth,
            true
        );
        final URI root = this.pth.toUri();
        Logger.info(this, "copyFilesTo(%s): root=%s", dst, root);
        while (iter.hasNext()) {
            final Path source = iter.next().getPath();
            final Path target = Folder.rebase(dst.path(), this.path(), source);
            Logger.info(
                this, "copyFilesTo(%s): src=%s target=%s",
                dst, source, target
            );
            FileUtil.copy(
                this.hdfs,
                source,
                dst.hdfs,
                target,
                false,
                true,
                this.hdfs.getConf()
            );
        }
    }

    /**
     * Change the base of target URI to new base, using root
     * as common path.
     * @param base New base
     * @param root Common root
     * @param target Target to rebase
     * @return Path with new base
     */
    static Path rebase(final Path base, final Path root, final Path target) {
        return new Path(
            base, root.toUri().relativize(target.toUri()).toString()
        );
    }

在集群中运行之后,我得到了以下日志:

代码语言:javascript
复制
io.Folder: copyFilesTo(hdfs:///tmp/_dst): from hdfs:///tmp/_src fs=DFS[DFSClient[clientName=DFSClient_NONMAPREDUCE_182008924_1, ugi=hadoop (auth:SIMPLE)]]
io.Folder: copyFilesTo(hdfs:///tmp/_dst): root=hdfs:///tmp/_src
INFO io.Folder: copyFilesTo(hdfs:///tmp/_dst): src=hdfs://ip-172-31-2-12.us-east-2.compute.internal:8020/tmp/_src/one.file target=hdfs://ip-172-31-2-12.us-east-2.compute.internal:8020/tmp/_src/one.file

我在rebase()方法中本地化了错误的代码,在EMR集群中运行时,它不能正常工作,因为RemoteIterator正在以远程格式返回URI:hdfs://ip-172-31-2-12.us-east-2.compute.internal:8020/tmp/_src/one.file,但是这个方法需要格式hdfs:///tmp/_src/one.file,这就是为什么它在本地使用file:/// FS。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-08-20 13:21:48

我不确定这是否是最好的和完全正确的解决方案,但它对我是有效的。其思想是在重基之前修复本地路径的主机和端口,工作的rebase方法将是:

代码语言:javascript
复制
    /**
     * Change the base of target URI to new base, using root
     * as common path.
     * @param base New base
     * @param root Common root
     * @param target Target to rebase
     * @return Path with new base
     * @throws IOException If fails
     */
    @SuppressWarnings("PMD.DefaultPackage")
    static Path rebase(final Path base, final Path root, final Path target)
        throws IOException {
        final URI uri = target.toUri();
        try {
            return new Path(
                new Path(
                    new URIBuilder(base.toUri())
                        .setHost(uri.getHost())
                        .setPort(uri.getPort())
                        .build()
                ),
                new Path(
                    new URIBuilder(root.toUri())
                        .setHost(uri.getHost())
                        .setPort(uri.getPort())
                        .build()
                        .relativize(uri)
                )
            );
        } catch (final URISyntaxException err) {
            throw new IOException("Failed to rebase", err);
        }
    }
票数 0
EN

Stack Overflow用户

发布于 2019-08-19 19:41:37

我看不出任何明显的错误。

  1. 是hdfs-hdfs还是s3a-s3a?
  2. 升级您的hadoop版本;2.7.x已经过时了,特别是在S3A代码中。它不太可能使这个问题消失,但它将避免其他问题。升级后,切换到快速上传,它将对大型文件进行增量更新;目前,您的代码将每个文件保存到某个地方,然后在close()调用中上传。
  3. 打开org.apache.hadoop.fs.s3a模块的日志记录,看看它说了什么
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57555082

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档