每 5 秒调用一次 Lambda 函数

Posted

技术标签:

【中文标题】每 5 秒调用一次 Lambda 函数【英文标题】:Invoking a Lambda function every 5 seconds 【发布时间】:2018-05-17 17:50:33 【问题描述】:

我的问题

出于某些监控目的,我想每 5 秒调用一次 AWS Lambda 函数。

根据the docs,

不支持少于一分钟的速率频率。

我尝试了什么

STFW。

我的问题

我可以每 5 秒自动调用一次 AWS Lambda 函数吗?

【问题讨论】:

抱歉,STFW 代表什么? 搜索 fine 网络。正如您想象的那样,类似的首字母缩写词也很流行 【参考方案1】:

虽然我不能推荐这种方式,但是如果你真的需要每 5 秒执行一次 Lambda 函数,你可以试试这个:

    创建一个每分钟执行一次的 Lambda 函数 A。 创建一个由 Lambda 函数 A 每 5 秒触发一次的 Lambda 函数 B。(A 触发 B,等待 5 秒,触发 B,等待 5 秒,...) 大约一分钟后停止 Lambda 函数 A。 (您可以阅读remaining miliseconds from the context object => 如果达到>55 秒,则停止执行)

如果你真的需要这个,请慎重考虑。

【讨论】:

只使用步进函数。 aws.amazon.com/blogs/architecture/…【参考方案2】:

您可以为此使用阶跃函数和 lambda - 查看 https://aws.amazon.com/blogs/architecture/a-serverless-solution-for-invoking-aws-lambda-at-a-sub-minute-frequency/

【讨论】:

这应该是现在的正确答案(尽管其他人提到的成本影响仍然相关) 需要注意的是,step 函数会在其执行历史日志中有 25k 个条目后自动停止(失败状态)。对于具有许多状态的阶跃函数,这可能会很快发生。 docs.aws.amazon.com/step-functions/latest/dg/…【参考方案3】:

我想我还是会回答这个问题。

您的整个问题是,无服务器不太适合几乎恒定的工作负载。它们更适合快速缩小和缩小。但是,如果这不是您的用例,那么您几乎可以肯定使用 ec2 实例在成本方面会更好,您甚至可以保留一个。但我确实知道您失去了 Lambda 的高可用性和其他一些好处,这可能希望您仍然采用这种方法。

如果您想使用大锤来实现这种方法,您可以使用 StepFunction。 StepFunction 可以以秒为单位等待,但唯一的问题是它们不会无限期运行并且会在 1 年后死亡,因此您的 StepFunction 需要在它死亡之前启动另一个 StepFunction,或者您将不得不通过其他一些机制,即云手表闹钟。

这种方法对于你所说的调用次数也需要一点钱,会花费超过

(31,540,000 [秒/年] / 5 [秒/调用] x $0.000025 = $157.7)

加上您的 Lambda 成本,(我认为您实际上需要 2 次状态转换,所以我认为您将这个数字加倍)

如果你只打算跑 1 可能没问题。但是如果说跑 100 会远远超过 10k!毫无疑问,一个 ec2 实例的成本会更低。

【讨论】:

“你的全部问题是无服务器不适合几乎恒定的工作负载。”我不认为这是真的,我们将 lambda 用于许多恒定的工作负载(例如流式传输/转换日志事件)。 这很好,但对于这种类型的工作负载,它并不是最具成本效益的架构。【参考方案4】:

以下是无服务器的全部内容,每秒钟执行一次步进函数 - 永远和一天:

service:
  name: your-service

plugins:
  - serverless-python-requirements
  - serverless-step-functions
  - serverless-pseudo-parameters

custom:
  pythonRequirements:
    dockerizePip: non-linux
  region: eu-west-1
  stage: dev

package:
  exclude:
    - node_modues/**
    - venv/**

provider:
  name: aws
  iamManagedPolicies:
    - arn:aws:iam::aws:policy/AWSStepFunctionsFullAccess
    - arn:aws:iam::aws:policy/AWSLambdaFullAccess
  runtime: python3.7
  versionFunctions: false
  region: $self:custom.region
  stage: $self:custom.stage
  environment:
    PUSH_FUNCTION: arn:aws:lambda:#AWS::Region:#AWS::AccountId:function:$self:service-$self:custom.stage-push
functions:

  schedulerStart:
    handler: scheduler.start
    events:
      - schedule: rate(1 minute)
    environment:
      STATEMACHINE_ARN: $self:resources.Outputs.SchedulerStateMachine.Value

  scheduler:
    handler: scheduler.handle

  push:
    handler: scheduler.push


stepFunctions:
  stateMachines:
    everySecond:
      name: SchedulerStateMachine
      definition:
        Comment: "Step Function invoked every minute"
        StartAt: ConfigureCount
        States:
          ConfigureCount:
            Type: Pass
            Result:
              index: 0
              count: 60
            ResultPath: "$.iterator"
            Next: "Iterator"
          Iterator:
            Type: Task
            Resource: "arn:aws:lambda:#AWS::Region:#AWS::AccountId:function:$self:service-$self:custom.stage-scheduler"
            ResultPath: "$.iterator"
            Next: "IsCountReached"
          IsCountReached:
            Type: Choice
            Choices:
              - Variable: "$.iterator.continue"
                BooleanEquals: true
                Next: "Wait"
            Default: "Done"
          Wait:
            Type: Wait
            Seconds: 1
            Next: "Iterator"
          Done:
            Type: Pass
            End: true

resources:
  Outputs:
    SchedulerStateMachine:
      Description: The ARN of the state machine
      Value:
        Ref: SchedulerStateMachine

scheduler.py

import os

import boto3

lambda_client = boto3.client('lambda')
step_functions_client = boto3.client('stepfunctions')


def start(event, context):
    step_functions_client.start_execution(stateMachineArn=os.environ['STATEMACHINE_ARN'])
    return 


def handle(event, context):
    index = event['iterator']['index'] + 1
    lambda_client.invoke(
        FunctionName=os.environ['PUSH_FUNCTION'],
        InvocationType='Event'
    )
    return 
        'index': index,
        'continue': index < event['iterator']['count'],
        'count': event['iterator']['count']
    

def push(event, context):
    print("Executed every seconds!")
    return

【讨论】:

需要注意的是,step 函数会在其执行历史日志中有 25k 个条目后自动停止(失败状态)。对于具有许多状态的阶跃函数,这可能会很快发生。 docs.aws.amazon.com/step-functions/latest/dg/… 这里适用吗? o avoid reaching this quota for long-running executions, implement a pattern that uses an AWS Lambda function that can start a new execution of your state machine -> 这正是我在这里所做的,每分钟重新开始。 我已经运行了一年,它从未停止过,所以可以说@MarcSmith 的评论在这里不适用。【参考方案5】:

假设重试或轻微的时间漂移​​不是世界末日。另一种可能的方法是每分钟 cron 一次编排 lambda,然后转身并创建延迟的 sqs 消息。然后,您可以使用 sqs lambda 触发器来调用您的目标 lambda。

使用 SQS SendMessage DelaySeconds API(它可能是所有 AWS sdk 的原生 API)作为想要进行的亚分钟调用次数的偏移量。例如,如果您想每 5 秒拨打一次电话,您将创建 12 条消息

    delaySeconds: 00 delaySeconds: 05 delaySeconds: 10 delaySeconds: 15 ...
https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html

使用这种方法,必须特别注意 sqs 的 lambda 调用和重试逻辑。如果多次尝试是一个问题,请确保设置 DLQ 并考虑使用 FIFO 队列。根据设计,AWS 可能会多次调用目标 lambda。请注意,标准 SQS 队列是:at-least-once delivery,而 FIFO 队列是:exactly-once processing。由于 CloudWatch 可能会在一分钟“之后”几秒钟调用编排 lambda,因此这种方法也可能会产生一些时间偏差。

https://aws.amazon.com/sqs/faqs/

这种方法是否比长时间运行编排 lambda 甚至阶跃函数更好?嗯,这取决于很多事情。就我个人而言,我发现让 lambda 处于等待状态的想法很浪费,你必须为那个 lambda 大部分时间什么都不做,如果它是一个很大的 lambda,那么这些成本并不是微不足道的。与 sqs 集成相比,使用 step 函数似乎有点矫枉过正,而且设置要复杂得多。

至少对我来说,最好让它启动,通过 sqs 安排一组任务然后死掉。这比长时间运行的 lambda 更复杂,有一些必须解决的并发问题,但如果这是人们想要的,它就是“无服务器”。

尽管如此,lambda 并不是最适合所有事情的——如果这是一项“永远”的任务,请考虑使用 ECS/Fargate/EC2,因为它很有可能更便宜,最终也不那么复杂。

【讨论】:

【参考方案6】:

Cron 只允许至少一分钟。您可以做的是编写一个带有无限循环的 shell 脚本来运行您的任务,然后休眠 5 秒。这样,您的任务将或多或少地每 5 秒运行一次,具体取决于任务本身需要多长时间。

但这听起来确实像是你在做一些你可能不应该做的事情。这感觉不对。

【讨论】:

虽然可以每 5 秒执行一次 Lambda 并且仍保留在免费层(假设 t2.small 或t2.micro 实例的成本。 没错,但我不必担心维护机器 - 安全性、可用磁盘空间、从错误中恢复、故障机器等。 FaaS 有其优势,即使它有点贵。【参考方案7】:

现在有一个使用 CloudWatch 事件规则的解决方法,它会每分钟触发一个 Step Function。然后,step 函数将触发给定次数的“迭代器”Lambda,它将调用您的 lambda。这是AWS blog post。

【讨论】:

每 10 秒调用一次:~$18 step function cost + lambda。每秒一次:~200 美元 + lambda 成本。当 lambda 运行约 400 毫秒时,这意味着您需要为 lambda 支付约 10 美元,为调用支付约 200 美元。相当昂贵的调度器【参考方案8】:

无论何时调用 lambda,假设是 1 分钟。将其除以 5 秒,您可以在调用 lambda 时保持可配置。

然后让循环等待并在处理程序内每 5 秒重复一次。 这样您就不需要任何新的 lambda 和 lambda 调用费用。

【讨论】:

以上是关于每 5 秒调用一次 Lambda 函数的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 QT 每 15 秒调用一次函数

golang 每2秒调用一次函数的两种方法

golang 每2秒调用一次函数的两种方法

如何每 x 秒调用一次方法?

Lambda冷启动可能的解决方案?

setInterval和setTimeout的区别