首页 文章

使用Lambda的AWS多个计划任务

提问于
浏览
1

我有以下应用场景 .

我需要根据多个用户操作和规则在我的服务器中调用API . 在我的网络应用程序中,用户可能会单击一个按钮,我需要在 X 时间之后安排一个事件,其中 X 值取决于用户配置 . 该事件必须触发对将处理某些数据的API的回调 .

为了实现这一目标,我使用 AWS 服务以多种方式思考 . 因此,一旦用户点击我的网络应用程序按钮服务器将:

SQS Approach

  • 创建 SQS 队列,然后每2分钟运行一次 Lambda 函数并按队列检查以查看元数据时间戳值是否准时执行API调用 . 完成API调用后,删除队列 .

这里的问题是我可以让10,000个并发用户单击它自己的按钮,这意味着10,000个队列,每个队列将有自己的元数据时间戳值,这是我在 Lambda 需要调用API时的预定时间 . 从阅读中无法根据元数据值查询 SQS :Ex . 获取时间戳等于或小于实际时间的所有队列 .

此外,我正在调查队列延迟功能,只能使需要执行的队列可见,但缺点是延迟最大值是15分钟,我可以有超过6小时的预定时间 .

DynamoDB Approach

  • 服务器将创建 DynamoDB 记录,而不是使用 SQS . 然后 Lambda 每2分钟执行一次,如果Timestamp成员等于或小于实际时间,将拉出所有表记录并循环验证每个表记录,如果是,则调用API并删除DB记录 .

这种情况可能看起来更好,因为我猜从 DynamoDB 获取记录的性能更快(是一种猜测)但又缺乏强大的查询,因为我只能查询主键 . 我正在阅读我可以扫描,但不知道是否可以根据日期和时间值进行扫描 .

Cloudwatch Approach

  • 而不是使用 SQSDynamoDB ,在每个用户按钮单击时,服务器必须创建 Cloudwatch 规则,该规则将具有我需要触发 Lambda 函数的预定时间 . 执行 Lambda 并调用API后, Lambda 将需要删除 Cloudwatch 规则,以便它不会再次执行 .

这个场景需要创建数以千计的 Cloudwatch 规则并且不知道这是否可行,但我喜欢这种方法,因为我不必拉数据,循环每个项目,验证时间戳并触发 Lambda ,因为 Cloudwatch 会自动执行 .

任何建议或线索,哪一个是正确的方法或可能我错过了其他人 . 谢谢

3 回答

  • 1

    我不会使用您概述的任何方法 . 相反,我会开发一个利用Amazon Step Functions的解决方案 .

    当用户单击该按钮时,实例化步骤功能,其中第一步骤之一是参数化等待状态 . 这将为您提供用户配置的等待时间,并且可以根据需要进行长或短 . 在等待状态之后,您可以在工作流程中执行其余步骤 .

    与使用步骤函数相比,您概述的所有方法都显得笨拙,易碎且昂贵 . 通过无服务器解答,您可以无缝扩展并高效运行 .

    https://docs.aws.amazon.com/step-functions/latest/dg/amazon-states-language-wait-state.html

  • 0

    Dynamo方法

    我认为这是你走的最佳方式 . 你实际上可以拥有所谓的composite primary key:“这种类型的键由两个属性组成 . 第一个属性是分区键,第二个属性是排序键” .

    例如,排序键可以是应该执行作业的时间戳 . 这样,您可以同时查询主键(也称为Hash属性) AND 排序键(也称为分区键),以便仅检索将在某个时间点执行的作业,而无需扫描 .

    OBS . : now() 将是一个返回当前时间戳的函数 .

    • 单击用户按钮后,生成应运行请求的时间戳(例如,从现在起5小时= now() + 60 * 60 * 5 )并将此时间戳保存为Dynamo中的排序键 .

    • 在Lambda函数中(每2分钟自动触发),您将查询Dynamo以使用 sort_key < now() 检索请求,这将检索将在该特定时间点执行的所有请求 .

    • 处理完成后,您将从Dynamo中删除请求或将其标记为已执行 .

    小心那个Dynamo限制单个查询中要返回的项目数以及查询结果的大小(以MB为单位) . 此外,Lambda的执行时间限制为5分钟 . 根据您的处理需要多长时间以及在某些时候处理的请求数量,您需要将其拆分为块,否则Lambda可能会超时 .

    这里可以使用各种方法:

    • 相同的Lambda函数在每个作业结束时调用自身以继续处理挂起的请求(如果're any). This is easier to implement, but the downside is when you have too many chunks: the latter ones would be delayed (they'll等待第一个作业执行) . 延迟可能会有问题,因为您的用户希望先前处理该作业 .

    • 您可以使用Composer函数从Dynamo中检索所有内容(可以运行多个查询,如果有太多待处理作业)并且并行多次触发另一个Lambda函数(在异步模式下) . 第二个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方法

    正如您已经表达的那样,SQS不是处理这种用例的工具 .

    Cloudwatch(CW)方法

    这里的问题是CW的限制为100 rules per region per account . 您可以申请增加,但我不允许您拥有多达数十或数十万条规则 . 它不适用于这种用例 .

    如果您的日程安排不需要粒度,您仍然可以通过设置可由不同用户共享的标准规则来使用CW . 例如:

    • 设置每小时运行24条规则,以便覆盖整天 . 您可以使用当天的小时来识别每个规则:"rule1:00AM","rule2:00AM"等 .

    • 让's say it'上午7点UTC,用户想要从现在起安排3小时 . 您将使用主键(如 rule10:00AM-reqXYZ123 )在Dynamo中保存此请求 .

    • 在上午10:00,相应的CW规则将触发Lambda,Lambda将从Dynamo检索所有具有以"rule10:00AM"开头的主键的请求(请参阅Conditional Queries中的BEGIN_WITH) . 然后,您可以在Lambda上正常处理请求 .

    • 处理完成后,您将从Dynamo中删除请求或将其标记为已执行 .

    还要遵守我上面提到的Dynamo和Lambda的相同限制 . 如果您需要更多粒度,则可以每30分钟运行48个CW规则,或者每15分钟运行96个CW规则 . 但无论如何,我更喜欢上面的Dynamo方法 . 它将花费您更多的时间来实现,但它更灵活,可重用 .

  • 1

    虽然你已经通过使用Step Function找到了答案,但我还是想分享我对此的看法,因为你的用例与我的用例非常相似,我最终使用的是DynamoDB .

    但是,我的方法不是使用Lambda来查询和验证时间戳,而是使用DynamoDB的生存时间(时间戳列设置为TTL),表中的记录将在到期时删除并删除记录将出现在DynamoDB流中 . 一旦它出现在流中,就可以触发Lambda进行进一步处理 . 您可以在此处找到有关TTLStream的文档 .

    因此,一般情况下,我的应用程序将通过在DynamoDB中添加记录来记录进程事件,并在事件发生时添加时间戳(时间戳为TTL) . 然后,一旦达到时间戳,DynamoDB将删除记录并将其放入将触发Lambda启动事件的流中 .

    使用这种方法的决定是因为我的应用程序需要能够"scheduled event"的另一个用例 . 所以只要记录还在表中,我仍然可以操纵它们 .

相关问题