将文件上传并压缩到s3

Posted

技术标签:

【中文标题】将文件上传并压缩到s3【英文标题】:uploading and compressing file to s3 【发布时间】:2014-07-26 21:42:58 【问题描述】:

我最近开始使用 S3,并且遇到了将大文件 (10 gb +-) 上传和压缩到 s3 的需求。 我正在使用的当前实现是在本地创建一个临时压缩文件,然后将其上传到 s3,最后删除临时文件。问题是,对于一个 10 GB 的文件,我在本地存储了将近 20 GB,直到上传完成。我需要一种将文件传输到 s3 然后在那里压缩的方法。 这种方法可行吗?如果是,我应该如何解决它?如果没有,有什么办法可以最小化所需的本地空间? 我见过有人建议将文件上传到 S3,下载到同一区域的 EC2,在那里压缩,然后上传回 S3,同时删除 S3 上的第一个副本。这可能行得通,但在我看来,为一个文件上传 2 次上传在成本上并不是一个优势。

我尝试上传压缩流但没有成功,但我刚刚发现 s3 不支持压缩流,现在我不知道如何继续。

我在 .NET 上使用 gzip 库

【问题讨论】:

【参考方案1】:

在 linux shell 中,通过 aws-cli,这是在您提出问题大约 3 个月后添加的 :-)

Added the ability to stream data using cp

所以我猜你能做的最好的就是将 gzip 的输出通过管道传输到 aws cli:

从标准输入上传:

gzip -c big_file | aws s3 cp - s3://bucket/folder/big_file.gz

下载到标准输出:

aws s3 cp s3://bucket/folder/big_file.gz - | gunzip -c ...

【讨论】:

非常有帮助 同样可以使用zip,使用-作为.zip文件名创建流:zip - big_file | aws s3 cp - s3://bucket/folder/big_file.zip 嗨,有没有办法使用s3cmdtar 来做到这一点?【参考方案2】:

如果您最初存储文件的位置的空间非常宝贵,则将文件上传到 S3,然后将文件下载、压缩并重新上传到与 S3 位于同一区域的 EC2 实例上的 S3 bucket 实际上是一个非常明智(如果看似违反直觉)的建议,原因很简单:

同一区域内 EC2 和 S3 之间的 AWS does not charge you for bandwidth。

这是 spot instance... 的理想工作,也是 SQS 告诉现场机器需要做什么的好用例。

另一方面...如果您不先压缩该文件,您将花费更多的本地带宽来上传该文件。

如果你是一名程序员,你应该能够制作一个类似于我编写的实用程序供内部使用(这不是一个插件;它目前不可用于发布),它可以压缩(通过外部工具)并即时将文件上传到 S3。

它的工作原理类似于以下伪代码示例命令行:

cat input_file | gzip -9c | stream-to-s3 --bucket 'the-bucket' --key 'the/path'

这是一个简化的用法示例,用于说明概念。当然,我的“stream-to-s3”实用程序接受许多其他参数,包括 x-amz-meta 元数据、aws 访问密钥和秘密,但也许你明白了。

gzip、pigz、bzip2、pbzip2、xz 和 pixz 等常用压缩实用程序都可以从 STDIN 读取源文件并将压缩数据写入 STDOUT,而无需将文件的压缩版本写入磁盘。

我使用的实用程序通过管道从其STDIN 读取文件数据,并使用 S3 Multipart Upload(即使对于技术上不需要它的小文件,因为 S3 Multipart Upload 巧妙地不需要您可以提前知道文件的大小),它只是不断地向 S3 发送数据,直到它在其输入流上达到EOF。然后它完成分段上传并确保一切成功。

我使用此实用程序构建和上传整个 tarball,并进行压缩,而无需触及单个磁盘空间块。同样,它并不是特别难写,而且可以用多种语言完成。我什至没有使用任何 S3 SDK,而是使用标准 HTTP 用户代理和 S3 API 文档从头开始开发自己的 SDK。

【讨论】:

OP 说“S3 不支持压缩流。”我不确定这真正意味着什么,但我知道我的答案不是理论上的。我每天都会将数十 GB 高度压缩的数据实时传输到 S3。 S3 支持通过分段上传有效地“流式传输”的内容,并且与上传内容的压缩性无关。 我的意思是上传时无法压缩。压缩的文件上传就好了。所以,如果我没看错的话,你的代码实际上可以读取文件流,压缩它并使用多部分上传(我熟悉这个功能),而无需使用临时文件? 我明白了。这就是我正在做的事情,上传一个压缩的文件,但我这样做是因为压缩算法会在管道上为我提供压缩数据。 我尝试使用包含压缩数据的流来压缩和馈送多部分。问题是,我没有设法让流程继续下去,最终得到了 3 个损坏的 .gz 文件,导致多部分将每个部分都作为一个文件关闭。也许我在某个时候弄乱了代码。在我让我的老板告诉我你不能部分压缩文件然后把它们放在一起之后,我想我可能会来这里寻求帮助。很高兴在这里看到与我的第一种方法如此相似的东西。 一个multipart upload 只可能在 S3 中创建一个文件(对象),所以如果你以某种方式结束了 3 个文件,那将是你的实现中的一个缺陷,而不是一般原则你正在尝试什么。【参考方案3】:

我需要一种方法将文件传输到 s3,然后在那里压缩。这种方法可行吗?

这种方法不可行/不是可选的。压缩会占用大量 CPU 资源,而 Amazon S3 的业务是存储数据,而不是对您的文件执行繁重的处理。

使用 S3,您还需要为上传的内容支付带宽,因此发送更多数据是浪费金钱。

我看到有人建议将文件上传到 S3,下载到同一区域的 EC2,在那里压缩,然后 上传回 S3,同时删除 S3 上的第一个副本。

您可以做的是直接上传到 EC2,在那里压缩,然后从那里上传到 S3。但现在您已将 20GB 问题从本地机器转移到 EC2 实例。

最好的方法是继续使用您当前在本地压缩然后上传的方法。

【讨论】:

【参考方案4】:

对于上传吞吐量而言,一个非常重要的 S3 功能是并行上传。有几个工具可以做到这一点,例如 aws cli、s3cmd 或 crossftp。在 .NET API 中,同样可以使用 TransferUtility 类实现

如果您确实需要压缩,请查看S3DistCP,这是一个可以使用多台机器并行传输并即时压缩的工具。

【讨论】:

【参考方案5】:

如果您使用的是 .NET,您可以创建一个字符流,但您仍然需要一些大于 20 GB 的本地存储空间。

另外,要成为亚马逊坏消息的承担者,S3 只是存储。您可能需要启动另一个服务 (aws),而不是运行可以在存储上压缩的程序。因此,您的应用使用 S3 存储上传和压缩。

如果您的项目较小,您可能需要考虑 IaaS 提供商而不是 PaaS。这样存储和应用程序可以在同一组服务器上。

【讨论】:

以上是关于将文件上传并压缩到s3的主要内容,如果未能解决你的问题,请参考以下文章

将目录作为压缩文件从 Elastic MapReduce 上传到 S3

上传 ZIP 文件到 S3,使用 EC2 解压

s3中图片打包后获取包地址

Boto3没有将zip文件上传到S3 python

在 S3 中上传输入流块后无法解压缩 gzip 文件

上传到 AWS S3 时,Java 中的最大文件上传大小是多少?