【问题标题】:S3 Lambda trigger double invocation after exactly 10 minutesS3 Lambda 在 10 分钟后触发双重调用
【发布时间】:2017-05-04 14:50:44
【问题描述】:

我们遇到了由 S3 ObjectCreated-Events 触发的 Lambda 的两次 Lambda 调用。这些双重调用恰好在第一次调用后 10 分钟发生,而不是在第一次尝试完成后 10 分钟,而是在第一次调用发生后 10 分钟。原始调用需要 0.1 到 5 秒之间的任何时间。没有调用导致错误,它们都成功完成。

我们知道,例如,SQS 不能保证只传递一次但至少传递一次消息,并且由于底层分布式系统的结果,我们会接受一些 lambdas 被第二次调用。然而,延迟 10 分钟听起来很奇怪。

在大约 10k 条消息中,100-200 条会导致两次调用。

AWS Support 基本上说“10 分钟的等待时间是设计使然,但我们无法告诉你原因”,这根本没有帮助。


  • 以前有没有其他人经历过这种行为?
  • 您是如何解决问题的,或者您只是忽略了它(我们可以这样做)?
  • 一种建议的解决方案是不使用直接 S3-lambda-triggers,而是让 S3 将其事件放在 SNS 上并订阅 Lambda。有使用这种方法的经验吗?

示例日志:两次调用,相隔 10 分钟,相同的 RequestId

START 请求 ID:f9b76436-1489-11e7-8586-33e40817cb02 版本:13
2017-03-29 14:14:09 INFO ImageProcessingLambda:104 - 处理 1 条记录

START 请求 ID:f9b76436-1489-11e7-8586-33e40817cb02 版本:13
2017-03-29 14:24:09 INFO ImageProcessingLambda:104 - 处理 1 条记录

【问题讨论】:

  • 正如您在问题中很好地描述的那样,“不保证完全一次但至少一次传递消息”,如果这不会破坏功能,那么您的第二个解决方案是最好的这点。我认为第三种解决方案没有任何区别,因为重复事件将再次提交给 SNS,因为订阅 Lambda 将简单地执行。如果您确实需要避免重复处理,您可以在 ElasticCache 或其他系统中的某个位置缓存“RequestIds”并添加签入 Lambda 以确保请求已被处理。
  • “AWS Support 基本上说...” 而不是解释一些对您来说没有意义的东西...他们实际上说了什么?
  • @Michael-sqlbot “我无法详细说明 S3 事件是如何在幕后实现的,但服务的行为符合预期,对于 S3 事件,10 分钟的延迟是设计使然” ,这样更有帮助吗??
  • @Nambari 在 lambda 中使用任何类型的缓存或逻辑来防止双重调用完全是矫枉过正。我们通常可以处理双重调用没有问题,请注意,在我们现在发送的几百万条 sqs 消息中,没有双重传递(如果真的发生的话)曾经引起过问题。两次调用之间的 10 分钟是个问题。我们可以将应用程序更改为能够处理延迟十分钟的消息,但这感觉不对,而且对理解这里发生的事情没有帮助。
  • 我明白了。谢谢你的澄清。这确实很奇怪,但似乎您已经正确诊断出真正的双重调用。在我的环境中,我使用 S3 > SNS > Lambda 而不是 S3 > Lambda,因为 (a) 有(或可能有)未来的目标想要相同的 S3 事件 (b) 它在某种程度上感觉更正确,我想知道这是否会改变动力学。我的过程是写入数据库,因此是有状态的和幂等的,所以重复调用实际上只是验证工作已经完成。但我会检查日志,因为我可能有一些有趣的事情......或者没有。

标签: amazon-web-services amazon-s3 aws-lambda eventtrigger


【解决方案1】:

经过几轮 AWS 支持和其他支持以及一些单独的试运行后,这似乎只是“设计使然”。目前尚不清楚为什么,但它只是发生了。问题既不是 S3 也不是 SQS / SNS,而只是 lambda 调用以及 lambda 服务如何将调用分派给 lambda 实例。

在第一次调用后 10 分钟,两次调用发生在所有调用的 1% 到 3% 之间。令人惊讶的是,甚至还有三次(可能是四次)调用,其概率是基本概率的幂,所以基本上是 0.09%,......三次调用发生在第一次调用后 20 分钟。

如果您遇到这种情况,您只需使用您可以访问的任何内容来解决它。例如,我们现在将已处理的实体存储在 TTL 为 1 小时的 Cassandra 中,并且仅在实体尚未处理时才响应来自 lambda 的消息。两次和三次调用都发生在这一小时的时间范围内。

【讨论】:

  • 我相信这是由于 AWS 服务的分布式特性。有不止一台服务器包含 SQS 事件,并且服务器之间的通信需要时间,因此一台服务器可能将其标记为已删除,但它在其他服务器上仍作为新服务器存在。因此,是的,这种行为是“设计”的
  • @MaxZoom 它与 SQS 无关,lambda 服务本身就是问题所在。在数百万个案例中,我们几乎从未收到重复的 SQS 消息。我很清楚 SQS 保证“至少一次”交付这一事实,但即使在那里,两次调用之间的延迟也不是 10!分钟。
【解决方案2】:

不想启动像 Dynamo 这样的数据存储来解决这个问题,我做了两件事来解决我们的用例

  • 将每个函数的锁定文件写入 S3(我们已经在这个函数中使用)并在函数入口检查它是否存在,如果存在则中止;对于这个函数,我们只希望一次运行其中一个。锁定文件在我们调用错误或成功回调之前被删除。
  • 在初始事件负载中写入请求时间,并在函数入口检查请求时间;如果请求时间太旧,则中止。我们不希望 Lambda 在错误时重试,除非它们很快完成,因此这可以处理发送重复或重试而同一函数的另一个调用尚未运行(这将被锁定文件停止)和在这种情况下,还避免了 S3 请求处理锁定文件的最小开销。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-24
    • 1970-01-01
    相关资源
    最近更新 更多