我有以下应用场景。
我需要根据多个用户操作和规则在我的服务器中调用API。在我的Web应用程序中,用户可能会单击一个按钮,我需要在X
时间X
值取决于用户配置后安排事件。该事件必须触发对将处理某些数据的API的回调。
为了实现这一点,我使用AWS
服务以多种方式思考。因此,一旦用户点击我的网络应用程序按钮服务器将:
SQS方法
SQS
队列,然后每2分钟运行一次Lambda
函数并按队列检查,以查看元数据时间戳值是否准时执行API调用。完成API调用后,删除队列。 这里的问题是我可以让10,000个并发用户点击它自己的按钮,这意味着10,000个队列,每个队列都有自己的元数据时间戳值,这是Lambda
需要调用API时的预定时间。从阅读开始,无法根据元数据值查询SQS
:Ex。获取时间戳等于或小于实际时间的所有队列。
此外,我正在调查队列延迟功能,只能使需要执行的队列可见,但缺点是延迟最大值为15分钟,我的预定时间可能超过6小时。
DynamoDB方法
SQS
记录,而不是使用DynamoDB
。然后每隔2分钟执行Lambda
并将拉出所有表记录并循环每个记录,如果Timestamp成员等于或小于实际时间则验证每个记录,如果是,则调用API并删除DB记录。 这种情况可能看起来更好,因为我认为从DynamoDB
获取记录的性能更快(是猜测)但又缺乏强大的查询,因为我只能查询主键。我正在阅读我可以扫描,但不知道是否可以根据日期和时间进行扫描。时间价值。
Cloudwatch方法
SQS
或DynamoDB
,而是在每次点击用户按钮时,服务器必须创建Cloudwatch
规则,该规则将在我需要Lambda
时具有预定时间功能被触发。执行Lambda
并调用API后,Lambda
将需要删除Cloudwatch
规则,以便不再执行该规则。 这种情况需要创建数以千计的Cloudwatch
规则,并且不知道这是否可行,但我喜欢这种方法,因为我不需要提取数据,循环每个项目,验证时间戳和触发Lambda
因为Cloudwatch
会自动执行此操作。
任何建议或线索,哪一个是正确的方法或可能我错过了其他人。感谢
答案 0 :(得分:1)
我认为这是你走的最佳方式。你实际上可以拥有所谓的composite primary key:“这种类型的密钥由两个属性组成。第一个属性是分区键,第二个属性是排序键”。< / p>
您的排序键可能是您应该执行作业的时间戳,例如。这样,您可以同时查询主键(也称为哈希属性) AND 排序键(也称为分区键),以便仅检索将在某个时间点执行的作业,无需扫描。
OBS。: now()
将是一个返回当前时间戳的函数。
now() + 60 * 60 * 5
)并将此时间戳保存为Dynamo中的排序键。sort_key < now()
的请求,该请求将检索将在该特定时间点执行的所有请求。 请注意,Dynamo会限制单个查询中要返回的项目数,并且整个查询结果的大小(以MB为单位)。此外,Lambda的执行时间限制为5分钟。根据您的处理需要多长时间以及在某些时候处理多少请求,您需要将其拆分为块,否则Lambda可能会超时,例如。
这里可以使用各种方法:
以下是作曲家函数在您的情况下将执行的操作的简单示例。我使用Python语法,但你应该很容易理解。
# In the Composer Lambda function:
# First, you'd get all scheduled tasks from DynamoDB
tasks = get_pending_tasks()
# Then you'd break it in multiple chunks before calling the Worker function
max_tasks_per_worker = 100
if len(tasks) <= max_tasks_per_worker:
call_worker(tasks=tasks)
elif len(tasks) > max_tasks_per_worker:
chunks = split_list(tasks, size=max_tasks_per_worker)
for chunk in chunks:
call_worker(tasks=chunk)
# split_list() just splits a list in chunks of n size
# Example: let's say you have a list of 240 items and want chunks of 100
# This function will return 3 lists with 100, 100, and 40 items each
# call_worker() just triggers another Lambda function that will actually
# execute the tasks that were scheduled
# You could use multiple threads to parallelize calls to the call_worker()
正如您已经表达的那样,SQS不是处理此类用例的工具。
这里的问题是CW的限制为100 rules per region per account。您可以请求增加,但我不会让您拥有多达数十或数十万条规则。它不适用于这种用例。
如果您的日程安排不需要粒度,您仍然可以通过设置可由不同用户共享的标准规则来使用CW。例如:
rule10:00AM-reqXYZ123
等主键在Dynamo中保存此请求。同样遵守我上面提到的Dynamo和Lambda的相同限制。如果您需要更多粒度,则可以每30分钟运行48个CW规则,或者每15分钟运行96个CW规则。但无论如何,我更喜欢上面的Dynamo方法。它将花费你更多的时间来实现,但它更灵活,更可重用。
答案 1 :(得分:1)
我不会使用您概述的任何方法。相反,我会开发一个利用Amazon Step Functions的解决方案。
当用户单击该按钮时,将实例化步骤功能,其中第一步之一是参数化等待状态。这将为您提供用户配置的等待时间,并且可以根据需要进行长或短。在等待状态之后,您可以在工作流程中执行其余步骤。
与使用步骤功能相比,您概述的所有方法都显得笨重,脆弱且昂贵。通过无服务器解答,您可以无缝扩展并高效运行。
https://docs.aws.amazon.com/step-functions/latest/dg/amazon-states-language-wait-state.html
答案 2 :(得分:0)
虽然你已经通过使用Step Function找到了答案,但我还是想分享我对此的看法,因为你的用例与我的用例非常相似,我最终使用的是DynamoDB。
但是,我的方法不是使用Lambda来查询和验证时间戳,而是使用DynamoDB的生存时间(时间戳列设置为TTL),表中的记录在到期时将被删除删除的记录将出现在DynamoDB流中。一旦它出现在流中,就可以触发Lambda进行进一步处理。您可以在此处找到有关TTL和Stream的文档。
因此,一般情况下,我的应用程序将通过在DynamoDB中添加记录来记录进程事件,并在事件发生时添加时间戳(时间戳为TTL)。然后,一旦达到时间戳,DynamoDB将删除记录并将其放入将触发Lambda启动事件的流中。
使用此方法的决定是因为我的应用程序需要能够查看/编辑/删除“预定事件”的另一个用例。所以只要记录仍在表格中,我仍然可以操纵它们。