Amazon SQS 死信队列 - Amazon Simple Queue Service
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

Amazon SQS 死信队列

Amazon SQS 支持死信队列 (DLQ),其他队列(源队列)可将其作为目标发送无法成功处理(使用)的消息。死信队列有助于调试您的应用程序或消息传递系统,因为它们可让您隔离未使用的消息以确定其处理失败的原因。有关使用 Amazon SQS 控制台配置死信队列的信息,请参阅配置死信队列(控制台)。一旦调试了使用者应用程序或使用者应用程序可供使用消息,您就可以使用死信队列重新驱动功能将消息移回源队列。

重要

Amazon SQS 不会自动创建死信队列。必须先创建队列,然后才能将其用作死信队列。

死信队列的工作方式

有时会因各种可能的问题(例如,创建者应用程序或使用者应用程序内的错误条件或导致您的应用程序代码出现问题的意外状态更改)而导致无法处理消息。例如,如果用户使用某特定产品 ID 下达 Web 订单,但产品 ID 已被删除,则 Web 商店的代码会失败并显示错误,而且包含订单请求的消息将发送到死信队列。

有时,创建者和使用者可能无法解释其用于通信的协议的各个方面,从而导致消息中断或丢失。此外,使用者的硬件错误可能会中断消息负载。

重新驱动策略指定源队列死信队列,以及 Amazon SQS 将消息从前者移至后者的条件(如果源队列的使用者无法处理消息指定次数)。maxReceiveCount 是使用者在移动到死信队列之前尝试从队列接收消息而不将其删除的次数。将 maxReceiveCount 设置为较低的值(例如 1)会导致无法接收消息,从而导致消息移至死信队列。此类故障包括网络错误和客户端依赖性错误。要确保您的系统能够抵御错误,请将 maxReceiveCount 设置得足够高,以允许足够的重试。

重新驱动允许策略指定哪些源队列可以访问死信队列。此策略适用于潜在死信队列。您可以选择是允许所有源队列、允许特定的源队列还是拒绝所有源队列。默认设置是允许所有源队列使用死信队列。如果您选择允许特定队列(使用 byQueue 选项),则可以使用源队列 Amazon 资源名称 (ARN) 最多指定 10 个源队列。如果您指定 denyAll,则队列不能用作死信队列。

要指定死信队列,您可以使用控制台或 Amazon SDK。您必须为将消息发送到死信队列的每个队列执行此操作。同一类型的多个队列可将一个死信队列作为目标。有关更多信息,请参阅配置死信队列(控制台) 以及 CreateQueueSetQueueAttributes 操作的 RedrivePolicyRedriveAllowPolicy 属性。

重要

FIFO 队列的死信队列也必须是 FIFO 队列。同样,标准队列的死信队列也必须是标准队列。

您必须使用相同的 Amazon Web Services 账户 来创建死信队列以及向死信队列发送消息的其他队列。此外,死信队列必须驻留在使用死信队列的其他队列所在的区域中。例如,如果在美国东部(俄亥俄州)区域中创建一个队列,并且要对该队列使用死信队列,则第二个队列也必须位于美国东部(俄亥俄州)区域中。

对于标准队列,消息的到期时间始终基于其原始入队时间戳。将消息移至死信队列时,入队时间戳保持不变。ApproximateAgeOfOldestMessage 指标指示消息何时移入死信队列,而不是消息最初发送的时间。例如,假设一条消息在原始队列中停留了 1 天,然后才移至死信队列。如果死信队列的保留期为 4 天,则消息将在 3 天后从死信队列中删除,且 ApproximateAgeOfOldestMessage 为 3 天。因此,最佳实践是始终将死信队列的保留期设置为比原始队列的保留期长。

对于 FIFO 队列,当消息移到死信队列时,入队时间戳会重置。ApproximateAgeOfOldestMessage 指标指示消息何时移动到死信队列。在上面的同一个示例中,消息在 4 天后从死信队列中删除,且 ApproximateAgeOfOldestMessage 为 4 天。

死信队列有哪些好处?

死信队列的主要任务是处理未使用消息的生命周期。利用死信队列,您可以留出和隔离无法正确处理的消息以确定其处理失败的原因。设置死信队列可让您执行以下操作:

  • 为移动到死信队列的任何消息配置警报。

  • 查看日志,以了解可能导致消息移动到死信队列的异常。

  • 分析移动到死信队列的消息内容,以诊断软件问题或创建者/使用者的硬件问题。

  • 确定是否为使用者提供了充足的时间来处理消息。

不同的队列类型如何处理消息失败?

标准队列

标准队列会在保留期结束前继续处理消息。这可确保连续处理消息,从而最大程度地减小队列由无法处理的消息阻止的几率。持续的消息处理还可以加快队列的恢复速度。

在一个处理数千条消息的系统中,存在使用者反复无法确认和删除的大量消息可能会增加成本并给硬件带来额外负载。最好是在几次处理尝试之后将失败的消息移至死信队列,而不是在这些消息到期前一直尝试处理它们。

注意

标准队列允许大量传输中消息。如果您的大多数消息无法使用且无法发送到死信队列,则处理有效消息的速率将下降。因此,要保持队列的效率,请确保应用程序正确处理消息。

FIFO 队列

FIFO 队列通过按顺序使用消息组中的消息,确保仅处理一次。因此,尽管使用者可继续检索另一个消息组中的有序消息,但在阻止队列的消息得到成功处理或移动到死信队列之前,第一个消息组将保持不可用状态。

注意

FIFO 队列允许少量传输中消息。因此,要确保您的 FIFO 队列不会被消息阻止,请确保应用程序正确处理消息。

当消息从 FIFO 队列移动到 FIFO DLQ 时,原始消息的重复数据删除 ID 将替换为原始消息的 ID。这是为了确保 DLQ 重复数据删除不会阻止存储恰好共享重复数据删除 ID 的两条独立消息。

何时应使用死信队列?

请将死信队列用于标准队列。当您的应用程序不依赖排序时,您应始终利用死信队列。死信队列可帮助您排查不正确的消息传输操作的问题。

注意

即使您使用死信队列,也应继续监控您的队列并重试发送因临时原因而失败的消息。

请使用死信队列来减少消息数和降低将系统公开给毒丸消息(可接收但无法处理的消息)的几率。

如果需要无限地重试传输消息,请不要对标准队列使用死信队列。例如,如果您的程序必须等待某个依赖过程变得有效或可用,请不要使用死信队列。

如果不想中断消息或操作的准确顺序,请不要对 FIFO 队列使用死信队列。例如,请不要对视频编辑套件的编辑决策列表 (EDL) 中的指令使用死信队列,此情况下,更改编辑的顺序将更改后续编辑的上下文。

将消息移出死信队列

您可以使用死信队列重新驱动来管理未使用消息的生命周期。在调查了标准或 FIFO 死信队列中未使用消息的属性和相关元数据后,您可以将消息重新驱动回其源队列。死信队列重新驱动通过在移动消息的同时批量处理消息来减少 API 调用计费。

重新驱动任务代表用户使用 Amazon SQS 的 SendMessageBatchReceiveMessageDeleteMessageBatch API 来重新驱动消息。因此,所有重新驱动的消息都被视为具有新 messageidenqueueTime 和保留期的新消息。死信队列重新驱动的定价使用调用的 API 调用次数和基于 Amazon SQS 定价的账单。

默认情况下,死信队列重新驱动会将消息从死信队列移动到源队列。但是,您还可以将任何其他队列配置为重新驱动目的地,前提是两个队列属于同一类型。例如,如果死信队列是 FIFO 队列,则重新驱动目的地队列也必须是 FIFO 队列。此外,您可以配置重新驱动速度以设置 Amazon SQS 移动消息的速率。有关配置死信队列重新驱动的说明,请参阅配置死信队列重新驱动

注意

Amazon SQS 不支持在将消息从死信队列中重新驱动时筛选和修改消息。

死信队列重新驱动任务最多可以运行 36 小时。Amazon SQS 支持每个账户最多 100 个活跃的重新驱动任务。

从 FIFO 死信队列中重新驱动消息时,消息 groupID 和 deduplicationID 保持不变,并且消息会收到一个新的 messageID。

Amazon SQS 死信队列按接收顺序重新驱动消息,从最旧的消息开始。但是,目标队列会根据接收消息的顺序摄取重新驱动的消息以及来自其他创建者的新消息。例如,如果创建者在向源 FIFO 队列发送消息的同时从死信队列接收重新驱动的消息,则重新驱动的消息将与创建者的新消息交织在一起。

排查死信队列的问题

在某些情况下,Amazon SQS 死信队列的行为可能并不总是符合预期。此部分概述了常见问题并说明如何解决这些问题。

使用控制台查看消息可能会导致消息移至死信队列

在控制台中根据相应队列的重新驱动策略查看消息时,Amazon SQS 将进行计数。因此,如果在控制台中查看消息的次数达到相应队列的重驱动策略中指定的次数,则该消息将移至相应队列的死信队列中。

要调整此行为,您可以执行下列操作之一:

  • 针对相应队列的重新驱动策略增大 Maximum Receives 设置。

  • 避免在控制台中查看相应队列的消息。

死信队列的 NumberOfMessagesSentNumberOfMessagesReceived 不匹配

如果您手动向死信队列发送消息,它将由 NumberOfMessagesSent 指标捕获。不过,如果因处理尝试失败而发送消息到死信队列,则此指标不会捕获该消息。因此,NumberOfMessagesSentNumberOfMessagesReceived 的值可能不同。

有关创建和配置死信队列重新驱动的信息

请注意,死信队列重新驱动需要您为 Amazon SQS 设置相应的权限,以接收来自死信队列的消息并将消息发送到目标队列。如果权限不足,则将死信队列重新驱动到源队列不会启动消息重新驱动,并可能使任务失败。您可以查看消息重新驱动任务的状态,以修复问题并重试。