我已经花了很多时间与AWS S3最近构建数据管道,并且遇到了S3存储桶中解压缩文件的令人惊讶的非平凡挑战。
与Google和Stackoverflow进行了几分钟,明确了许多其他人面临同一问题。
我将解释一些处理解压缩的选项以及导致我构建nejckorasa/s3-stream-unzip的最终解决方案。
总结:
- 没有支持S3中的解压缩文件,
- AWS SDK中也没有UNZIP内置API。
为了解压缩,您需要从S3下载文件,解压缩和上传解压缩文件。
使用Java AWS SDK,该解决方案易于实现,如果您要处理较小的文件,则可能足够好 - 如果文件足够小,您只需将解剖的文件保留在内存中并将其上传回去即可。
另外,如果有内存约束,则可以将文件持续到磁盘存储。太好了,有效。
较大的文件出现问题。 AWS Lambda,例如has a 1024MB memory and disk space limit。专用的EC2实例将解决磁盘空间问题,但需要更多的维护。我还认为将500MB+文件存储到磁盘上不是最佳方法。
当然,这将取决于需要解压缩多少个文件以及该操作的运行频率 - 这是一次性的,但如果需要每天运行,也许不是这样。无论如何,我们真的可以做得更好。
流解决方案
更好的方法是将文件从S3流式传输,将其下载,解压缩并将其上传回到使用Multipart上传的S3。这样,您就完全避免了需要磁盘存储的需求,并且可以通过调整下载和上传块尺寸来最大程度地减少内存足迹。
该解决方案的两个部分需要集成:
1)下载和uznip
流S3对象由AWS SDK本地支持,有一个getObjectContent()
方法返回包含S3对象内容的输入流。
Java提供ZipInputStream作为输入流滤波器,用于读取zip文件格式的文件。它读取逐渐进入的邮政编码,因此允许每个条目进行自定义处理。
从s3中流对象内容并将其馈送到ZipInputStream
中,我们可以在内存中缓冲我们可以缓冲的对象内容的块。
2)将未拉链的块上传到S3
将文件上传到S3是一项常见的任务,SDK支持几个选择,包括multipart upload。
什么是多部分上传?
Multipart上传允许您将单个对象作为一组零件上传。
每个部分都是对象数据的连续部分。您可以独立和任何顺序上传这些对象零件。
如果任何零件的传输失败,您可以在不影响其他零件的情况下重新发送该零件。上传对象的所有部分后,Amazon S3组装了这些零件并创建对象。
通常,当您的对象大小达到100 MB时,您应该考虑使用Multipart上传而不是将对象上传到单个操作中。
nejckorasa/s3-stream-unzip
现在剩下要做的就是集成流下载,解压缩和多部分上传。
我已经完成了所有的辛勤工作,并建立了nejckorasa/s3-stream-unzip。
java库,用于管理AWS S3中大型文件和数据的解压缩,而无需事先知道大小,也不将其全部保留在记忆或写入磁盘中。
无需事先知道大小,而不将其全部保留在记忆或写入磁盘上。这使其适用于大型数据文件 - 它已用于解开100GB+。
的拉链文件。它支持不同的解压缩策略,包括分配zipperiped文件的选项(适用于较大的文件,例如CSV文件)。它是轻巧的,仅需要Amazons3客户端。
它具有简单的API:
// initialize AmazonS3 client
AmazonS3 s3CLient = AmazonS3ClientBuilder.standard()
// customize the client
.build()
// create UnzipStrategy
var strategy = new NoSplitUnzipStrategy();
var strategy = new SplitTextUnzipStrategy()
.withHeader(true)
.withFileBytesLimit(100 * MB);
// or create UnzipStrategy with additional config
var config = new S3MultipartUpload.Config()
.withThreadCount(5)
.withQueueSize(5)
.withAwaitTerminationTimeSeconds(2)
.withCannedAcl(CannedAccessControlList.BucketOwnerFullControl)
.withUploadPartBytesLimit(20 * MB)
.withCustomizeInitiateUploadRequest(request -> {
// customize request
return request;
});
var strategy = new NoSplitUnzipStrategy(config);
// create S3UnzipManager
var um = new S3UnzipManager(s3Client, strategy);
var um = new S3UnzipManager(s3Client, strategy.withContentTypes(List.of("application/zip"));
// unzip options
um.unzipObjects("bucket-name", "input-path", "output-path");
um.unzipObjectsKeyMatching("bucket-name", "input-path", "output-path", ".*\\.zip");
um.unzipObjectsKeyContaining("bucket-name", "input-path", "output-path", "-part-of-object-");
um.unzipObject(s3Object, "output-path");
库可在Maven Central和Github上找到。
您可以在此处查看原始博客文章:https://nejckorasa.github.io/posts/s3-unzip/