AWS Beanstalk:SQS 的指数退避?

Posted

技术标签:

【中文标题】AWS Beanstalk:SQS 的指数退避?【英文标题】:AWS Beanstalk: Exponential backoff for SQS? 【发布时间】:2015-09-23 01:20:41 【问题描述】:

我们正在使用 Beanstalk 上的工作层来发送 webhook。我们需要使用指数退避,以防在联系第三方时出现任何错误。但是,我不清楚这将如何工作。

如果作业失败并且我调用ChangeMessageVisibility 来增加时间退避时间,我有两个选择:

    返回成功 200。然后 SQS 会将其从队列中移除 - 不好。 返回错误代码。那么 SQS 会将消息可见性覆盖为默认值吗?

来自Environment Tiers - AWS Beanstalk:

工作环境层中的 Web 应用程序应该只监听 本地主机。当工作环境中的 web 应用程序 tier 返回一个 200 OK 响应以确认它已收到并且 成功处理请求,守护进程发送 DeleteMessage 调用 SQS 队列,以便从 队列。 (SQS 会自动删除已经在队列中的消息 长于配置的 RetentionPeriod。)如果应用程序 返回 200 OK 以外的任何响应,然后 Elastic Beanstalk 等待 在配置完成后将消息放回队列中 可见性超时时间。如果没有响应,则 Elastic Beanstalk 等待将消息放回队列中 InactivityTimeout 时间段,以便消息可用于另一个 尝试处理。

【问题讨论】:

您应该在调用第三方时添加指数回退,而不是通过更改 sqs 消息超时 我不能让工人坐 24 小时,因为它在通话中后退。这就是 SQS 的用途。我能想出的唯一解决方案是,如果调用未能成功返回并再次排队相同的作业并增加可见性时间......比它应该的更复杂。 为什么要等 24 小时?指数退避设计为秒,而不是小时。 不一定。指数回退是过程而不是时间限制。如果您打电话给第三方以获取网络挂钩,那么在 1 分钟、15 分钟、一个小时、几个小时、一天放弃是非常有意义的。即使退避时间只达到 60 秒,也浪费了工人的时间坐在那儿整整一分钟无所事事。 【参考方案1】:

ChangeMessageVisibility 有 12 小时的限制,并且仅适用于 inflight 作业(在运行时您想通知 SQS“我需要更多时间来完成此任务”的作业)。

唯一的解决方案是在队列中创建一个具有相同详细信息和一个额外的重试计数器(在消息中或作为属性)的新作业,并使用基于 retries + 1 的具有指数退避的 DelaySeconds。

很遗憾,DelaySeconds 有 15 分钟(900 秒)的限制,因此您可以选择比这更长的时间来安排工作:

    继续每 15 分钟重新安排一次作业,但在重试次数达到足够高之前不要执行该任务。这将运行 95 个工作,这些工作在 96 日之前什么都不做。这可能会产生大量的虚拟工作。 一旦达到最小时间戳,将作业放在其他位置(如数据库或缓存),然后使用 cron 或其他一些计划进程将其放回队列中。例如,时间戳为 now + 1 天。

【讨论】:

我正在尝试实现类似的指数退避效应(使用 Camel 而不是 Beanstalk)。我遇到的问题是,当我创建消息的副本以与DelaySeconds 一起返回到 SQS 时,它的接收计数被重置回 0(因为它是一条新消息)。所以我的消息接收计数永远不会大于 1,因此它们会被无休止地重试,而不是被 DLQed。知道如何在考虑最终 DLQ 的同时完成此任务吗?【参考方案2】:

增加失败作业的 ChangeMes​​sageVisibility 有利有弊:

优点:

在移除和重新排队的过程中,您不会丢失作业。

缺点:

正在进行的作业的 12 小时限制。 您一次只能有 20k 个飞行任务

因此,如果作业失败太多次,减轻缺点的一个想法是为 dlq 设置重新驱动策略。

【讨论】:

以上是关于AWS Beanstalk:SQS 的指数退避?的主要内容,如果未能解决你的问题,请参考以下文章

AWS Elastic Beanstalk Worker 无法连接到 SQS

AWS 中的错误重试和指数退避

算法6指数退避算法

AWS Elastic Beanstalk Worker 队列行为

二进制指数退避算法

指数退避和AIMD为什么都青睐数字2