AWS - 希望上传多个文件到S3,只有当所有文件都上传完成后才触发Lambda函数。

19

我正在寻求有关设计方式的建议 -

使用案例

我想将多个文件放入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

选项3与S3触发器 我担心这里可能会出现竞态条件。例如,如果客户端同时上传多个文件(考虑同时启动几个异步上传,文件大小不同),如果两个文件恰好在同一时间结束上传,那么两个或多个Lambda函数(或使用的任何实现)查询Dynamo并返回已完成上传的数量N(而不是N和N+1),现在即使最终结果应该是N+2,每个都会向N添加1。不行啊!

所以选项1胜出。


选项1绝对是最优雅的解决方案。我很高兴你选择了这个。如果使用DynamoDB原子计数器并检查更新的返回结果而不是执行单独的查询,选项3中就不应该有竞态条件。我在我的答案中尝试通过链接到原子计数器文档来表达清楚这一点。 - Mark B
1个回答

5
如果您不想让客户端程序直接调用Lambda函数,那么如果它做一些更通用的事情,这样可以吗?
选项1:(SNS)如果它只是通知一个SNS主题已完成一批S3上传,那会怎样?您可以订阅Lambda函数到该SNS主题。
选项2:(DynamoDB Streams)如果它只是更新DynamoDB记录,例如一个属性record.allFilesUploaded = true。您可以使Lambda函数触发DynamoDB流。由于您已经通过客户端创建了DynamoDB记录,因此这似乎是一种非常简单的方法来标记上传批次为已完成,而无需编写有关需要发生什么的知识。然后,Lambda函数可以检查“allFilesUploaded”属性,而不必每次调用时都去S3获取文件列表。
或者,直到所有文件都上传完成后再插入DynamoDB记录,然后您的Lambda函数就可以触发新记录的创建。
选项3:(继续使用S3触发器)如果客户端程序不能从现有方式进行更改,那么在每次出现新文件时,不要列出所有S3文件并将其与DynamoDB中的列表进行比较,而是通过原子计数器更新DynamoDB记录。然后将结果值与文件列表的大小进行比较。一旦两个值相同,您就知道所有文件都已上传。这样做的缺点是您需要在DynamoDB表上提供足够的容量来处理所有更新,这将增加您的成本。
另外,我同意您的观点,SWF对于此任务来说过于复杂了。

对于你的建议,我在我的原帖中添加了评论。将其标记为答案。非常感谢你写下这些内容 - 这很有帮助。 - Beebunny
我正在使用第三个选项,通过S3触发器调用Lambda函数将对象下载到EFS,并且我遇到了以下问题。当我使用FileZilla客户端上传多个文件到S3时,Lambda被成功调用并工作,它会下载文件但不是所有已上传的文件,当我检查CloudWatch日志时,我发现某些对象出现了超时错误。 错误信息:[ERROR] ConnectTimeoutError: Connect timeout on endpoint URL: "https://*bucket_name*.s3.eu-west-1.amazonaws.com/*object* - Chawki
@Chawki 听起来你应该在这个网站上单独发一个问题,而不是试图在评论区寻求帮助。 - Mark B

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接