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

我的问题

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

根据the docs

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

我尝试了什么

STFW。

我的问题

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

【问题讨论】:

  • 抱歉,STFW 代表什么?
  • 搜索 fine 网络。正如您想象的那样,类似的首字母缩写词也很流行

标签: amazon-web-services cron aws-lambda


【解决方案1】:

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

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

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

【讨论】:

【解决方案2】:

【讨论】:

  • 这应该是现在的正确答案(尽管其他人提到的成本影响仍然相关)
  • 需要注意的是,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 条消息

  1. delaySeconds: 00
  2. delaySeconds: 05
  3. delaySeconds: 10
  4. delaySeconds: 15
  5. ...

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

这种方法是否比长时间运行编排 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 调用费用。

    【讨论】:

      猜你喜欢
      • 2023-03-26
      • 1970-01-01
      • 2011-11-06
      • 2011-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-16
      • 2019-04-21
      相关资源
      最近更新 更多