使用Lambda

时间:2018-02-04 05:39:47

标签: amazon-web-services aws-lambda amazon-dynamodb message-queue

我有以下应用场景。

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

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

SQS方法

  1. 创建一个SQS队列,然后每2分钟运行一次Lambda函数并按队列检查,以查看元数据时间戳值是否准时执行API调用。完成API调用后,删除队列。
  2. 这里的问题是我可以让10,000个并发用户点击它自己的按钮,这意味着10,000个队列,每个队列都有自己的元数据时间戳值,这是Lambda需要调用API时的预定时间。从阅读开始,无法根据元数据值查询SQS:Ex。获取时间戳等于或小于实际时间的所有队列。

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

    DynamoDB方法

    1. 服务器将创建SQS记录,而不是使用DynamoDB。然后每隔2分钟执行Lambda并将拉出所有表记录并循环每个记录,如果Timestamp成员等于或小于实际时间则验证每个记录,如果是,则调用API并删除DB记录。
    2. 这种情况可能看起来更好,因为我认为从DynamoDB获取记录的性能更快(是猜测)但又缺乏强大的查询,因为我只能查询主键。我正在阅读我可以扫描,但不知道是否可以根据日期和时间进行扫描。时间价值。

      Cloudwatch方法

      1. 不是使用SQSDynamoDB,而是在每次点击用户按钮时,服务器必须创建Cloudwatch规则,该规则将在我需要Lambda时具有预定时间功能被触发。执行Lambda并调用API后,Lambda将需要删除Cloudwatch规则,以便不再执行该规则。
      2. 这种情况需要创建数以千计的Cloudwatch规则,并且不知道这是否可行,但我喜欢这种方法,因为我不需要提取数据,循环每个项目,验证时间戳和触发Lambda因为Cloudwatch会自动执行此操作。

          

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

3 个答案:

答案 0 :(得分:1)

Dynamo方法

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

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

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

  1. 点击用户按钮后,生成请求应运行的时间戳(例如,从现在起5小时= now() + 60 * 60 * 5)并将此时间戳保存为Dynamo中的排序键。
  2. 在您的Lambda函数中(每2分钟自动触发),您将查询Dynamo以检索sort_key < now()的请求,该请求将检索将在该特定时间点执行的所有请求。
  3. 处理完成后,您将从Dynamo中删除请求或将其标记为已执行。
  4. 请注意,Dynamo会限制单个查询中要返回的项目数,并且整个查询结果的大小(以MB为单位)。此外,Lambda的执行时间限制为5分钟。根据您的处理需要多长时间以及在某些时候处理多少请求,您需要将其拆分为块,否则Lambda可能会超时,例如。

    这里可以使用各种方法:

    • 相同的Lambda函数在每个作业结束时调用自身以继续处理挂起的请求(如果有的话)。这更容易实现,但缺点是当你有太多的块时:后者会被延迟(它们将等待第一个被执行)。延迟可能会有问题,因为您的用户希望早些时候处理该作业。
    • 您可以使用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。例如:

    1. 设置每小时运行24条规则,以便覆盖整天。您可以使用当天的小时来识别每个规则:“rule1:00AM”,“rule2:00AM”等。
    2. 让我们说它是UTC时间上午7点,并且用户想要从现在开始计划3小时。您将使用rule10:00AM-reqXYZ123等主键在Dynamo中保存此请求。
    3. 在上午10:00,相应的CW规则将触发Lambda,Lambda将从Dynamo检索所有具有以“rule10:00AM”开头的主键的请求(请参阅Conditional Queries中的BEGIN_WITH)。然后,您可以在Lambda上正常处理请求。
    4. 处理完成后,您将从Dynamo中删除请求或将其标记为已执行。
    5. 同样遵守我上面提到的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进行进一步处理。您可以在此处找到有关TTLStream的文档。

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

使用此方法的决定是因为我的应用程序需要能够查看/编辑/删除“预定事件”的另一个用例。所以只要记录仍在表格中,我仍然可以操纵它们。