AWS - 想要将多个文件上传到 S3,并且只有在所有文件都上传后才会触发 lambda 函数
Posted
技术标签:
【中文标题】AWS - 想要将多个文件上传到 S3,并且只有在所有文件都上传后才会触发 lambda 函数【英文标题】:AWS - want to upload multiple files to S3 and only when all are uploaded trigger a lambda function 【发布时间】:2016-03-26 09:46:03 【问题描述】:我正在就设计这个的最佳方式寻求建议 -
用例
我想将多个文件放入 S3。一旦所有文件都成功保存,我想触发一个 lambda 函数来做一些其他的工作。
天真的方法
我解决此问题的方法是在 Dynamo 中保存一条记录,该记录包含唯一标识符和我将上传的记录总数以及 S3 中应该存在的键。
一个基本的实现是使用我现有的 lambda 函数,该函数在我的 S3 存储桶被写入时调用,并让它手动检查是否所有其他文件都已保存。
Lambda 函数会知道(查看 Dynamo 以确定我们要查找的内容)并查询 S3 以查看其他文件是否在其中。如果是,请使用 SNS 触发我的其他 lambda 来完成其他工作。
编辑:另一种方法是让我将文件放入 S3 的客户端程序负责直接调用另一个 lambda 函数,因为从技术上讲,它知道所有文件何时已上传。这种方法的问题是我不希望这是客户端程序的责任......我希望客户端程序不在乎。一旦它上传了文件,它应该能够退出。
想法
我认为这不是一个好主意。主要是因为 Lambda 函数应该是轻量级的,并且从 Lambda 函数中轮询数据库以获取所有上传文件的 S3 密钥,然后检查 S3 是否存在 - 每次都这样做似乎是贫民窟而且非常重复。
什么是更好的方法?我正在考虑使用 SWF 之类的东西,但不确定这是否对我的解决方案来说太过分了,或者它是否会让我做我想做的事。该文档也没有显示真正的“示例”。这只是一个讨论,没有太多的分步指南(也许我找错了地方)。
编辑响应mbaird的以下建议-
选项 1 (SNS) 这就是我将采用的方法。这很简单,并没有真正违反单一责任原则。也就是说,客户端上传文件并发送通知(通过 SNS)它的工作已完成。
选项 2(Dynamo 流) 所以这本质上是选项 1 的另一个“实现”。客户端进行服务调用,在这种情况下,会导致表更新与 SNS 通知(选项1)。此更新将触发 Lambda 函数,而不是通知。不错的解决方案,但我更喜欢使用 SNS 进行通信,而不是依赖数据库的功能(在本例中为 Dynamo 流)来调用 Lambda 函数。
在任何情况下,我都在使用 AWS 技术并与他们的产品(Lambda 函数、SNS 等)耦合,但我觉得依赖 Dynamo 流之类的东西使其耦合更加紧密。对我的用例来说并不是一个大问题,但仍然感觉很脏;D
带有 S3 触发器的选项 3 我担心的是竞争条件的可能性。例如,如果客户端同时上传多个文件(想想几个文件大小不同的异步上传同时触发),如果两个文件恰好同时完成上传,以及两个或多个 Lambda 函数(或我们使用的任何实现)查询 Dynamo 并返回 N 作为完成的上传(而不是 N 和 N+1)?现在即使最终结果应该是 N+2,但每一个都会在 N 上加 1。Nooooooooooo!
所以选项 1 获胜。
【问题讨论】:
选项 1 绝对是最优雅的解决方案。我很高兴你能接受。如果您使用 DynamoDB 原子计数器,则选项 3 中不应存在竞争条件,并检查更新的返回结果而不是执行单独的查询。我试图通过链接到原子计数器文档在我的回答中明确这一点。 【参考方案1】:如果您不希望客户端程序负责直接调用 Lambda 函数,那么它是否可以做一些更通用的事情?
选项 1:(SNS) 如果它只是通知一个 SNS 主题它已完成一批 S3 上传怎么办?您可以将您的 Lambda 函数订阅到该 SNS 主题。
选项 2:(DynamoDB 流) 如果它只是简单地使用属性 record.allFilesUploaded = true
更新 DynamoDB 记录会怎样。您可以使用 Lambda 函数trigger off the DynamoDB stream。由于您已经通过客户端创建了 DynamoDB 记录,这似乎是一种非常简单的方法,可以将批量上传标记为完成,而无需编写关于下一步需要发生什么的知识。然后,Lambda 函数可以检查“allFilesUploaded”属性,而不必在每次调用时都去 S3 获取文件列表。
或者,在所有文件完成上传之前不要插入 DynamoDB 记录,那么您的 Lambda 函数可能会触发正在创建的新记录。
选项 3:(继续使用 S3 触发器)每次出现新文件时,DynamoDB 只需通过atomic counter 更新 DynamoDB 记录。然后将结果值与文件列表的大小进行比较。一旦值相同,您就知道所有文件都已上传。这样做的缺点是您需要在 DynamoDB 表上预置足够的容量来处理所有更新,这会增加您的成本。
另外,我同意你的观点,SWF 对于这项任务来说太过分了。
【讨论】:
将 cmets 添加到我关于您的建议的原始帖子中。将此标记为答案。非常感谢您将其写出来 - 这非常有帮助。以上是关于AWS - 想要将多个文件上传到 S3,并且只有在所有文件都上传后才会触发 lambda 函数的主要内容,如果未能解决你的问题,请参考以下文章
从(AngularJS)单页应用程序直接(并且简单!)AJAX 上传到 AWS S3