【问题标题】:Move millions of files to root of S3将数百万个文件移动到 S3 的根目录
【发布时间】:2018-09-03 12:33:32
【问题描述】:

我有 2000 万个本地文件。每个文件都由一个经过哈希处理的数字 ID 表示。

文件 1 被命名为 356a192b7913b04c54574d18c28d46e6395428ab (sha1 of "1")

文件 2 被命名为 da4b9237bacccdf19c0760cab7aec4a8359010b0(“2”的 sha1)

等等。等等

不是每个数字都代表一个文件,但我有一个所有数字的列表。

文件被放置在以哈希中的前两个字符命名的文件夹中,然后是接下来的两个,然后是接下来的两个。

对于文件 1 (da4b9237bacccdf19c0760cab7aec4a8359010b0),文件夹结构为

da/4b/92/

在那个文件夹中,文件被放置并且它被命名为完整的哈希,所以文件的完整路径是

da/4b/92/da4b9237bacccdf19c0760cab7aec4a8359010b0

我现在想将所有文件从文件系统移动到 Amazon S3 的存储桶中,并且同时我想将它们移动到该存储桶的根目录。

由于文件太多,如果有一种方法可以记录哪些文件已被移动以及哪些文件可能因某种原因而失败,我需要能够在失败时恢复操作。

p>

我的计划是在 mysql 中创建一个名为 moved_files 的表,然后运行一个 PHP 脚本,该脚本从 files 表中获取 X 个 ID,如果成功,则使用 AWS SDK for PHP 将文件复制到 S3它将该 ID 添加到 moved_files 表中。但是我不确定这是否是最快的方法,也许我应该考虑使用 AWS Cli 编写一个 bash 脚本。

任何建议将不胜感激!

【问题讨论】:

  • 这是一个 linux 机器吗?如果是这样,请使用 sh
  • 是的。我确实在我的问题结尾提到了使用 AWS Cli,但我不确定究竟如何做到这一点。首先,我需要确保所有文件都位于 S3 的根目录中,而不仅仅是服务器上文件结构的副本。然后我还想确保逐个移动文件是最好的方法,我在想也许有一种方法可以移动许多文件,而不必为每个文件打开到 S3 的新连接等
  • 使用“find + aws cli + echo 记录哪些文件已成功传输”。伪代码是: for file in $(find /my/dirs/ -type f);do aws s3 cp $file s3://my-bucket/ && echo "successfully mapped $file over" || echo "复制 $file 失败";完成
  • 移动成功后在本地删除文件怎么样,如果被打断了,本地仍然存在的文件都没有被移动。
  • 我怀疑 GNU Parallel 可能是确保您不断并行移动 4-8 个文件并占用所有可用带宽的好方法。

标签: php bash amazon-web-services amazon-s3 file-io


【解决方案1】:

我不使用 AWS S3,但在 Google 上搜索一下建议您需要如下命令:

aws s3 cp test.txt s3://mybucket/test2.txt

因此,如果您想为所有文件运行它,我建议您使用 GNU Parallel 来充分利用您的连接并减少延迟。

请创建一个包含几十个文件的测试目录进行测试,然后cd 到该目录并尝试以下命令:

find . -type f -print0 | parallel -0 --dry-run aws s3 cp {} s3://rootbucket/{/}

样本输出

aws s3 cp ./da/4b/92/da4b9237bacccdf19c0760cab7aec4a8359010b0 s3://rootbucket/da4b9237bacccdf19c0760cab7aec4a8359010b0
aws s3 cp ./da/4b/92/da4b9237bacccdf19c0760cab7aec4a8359010b1 s3://rootbucket/da4b9237bacccdf19c0760cab7aec4a8359010b1

如果您有 8 个 CPU 内核,那么它​​将一次运行 8 个 aws 的并行副本,直到您的所有文件都被复制。

{} 扩展为表示“当前文件”,{/} 扩展为表示“没有目录的当前文件”。也可以添加--bar获取进度条。

如果这看起来很有希望,我们可以为每个更新数据库或删除本地文件的文件添加一个小bash 函数,条件是aws 命令成功。看起来像这样 - 从底部开始阅读 ;-)

#!/bin/bash

# bash function to upload single file
upload() {
   local="$1"                                         # Pick up parameters
   remote="$2"                                        # Pick up parameters
   echo aws s3 cp "$local" "s3://rootbucket/$remote"  # Upload to AWS
   if [ $? -eq 0 ] ; then
      : # Delete locally or update database with success
   else
      : # Log error somewhere
   fi
}

# Export the upload function so processes started by GNU Parallel can find it
export -f upload

# Run GNU Parallel on all files
find . -type f -print0 | parallel -0 upload {} {/}

【讨论】:

  • 有 --recursive 标志来移动文件夹
  • @titogeo 谢谢 - 虽然 AFAIK,OP 想要删除文件夹名称。
  • @titogeo 另外,OP 想要单独检查和记录每个文件的成功,所以我不确定如果我们一次递归地执行整个目录会如何工作。
  • 您需要 S3 副本的存储桶名称,例如:aws s3 cp a/b/c/xyz s3://mybucket/xyz。
  • @jarmod 哦,我明白了!感谢您的更正 - 我会尽快更新。我有点想根存储桶没有命名!正如我所说,我不使用aws。再次感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-09
  • 2019-05-07
相关资源
最近更新 更多