

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

# Amazon SQS 最佳实践
<a name="sqs-best-practices"></a>

Amazon SQS 可以管理和处理消息队列，使应用程序的不同部分能够可靠且大规模地交换消息。本主题提供了关键的操作最佳实践，包括使用长轮询来减少空响应、实施死信队列来处理错误，以及优化队列权限以确保安全。

****主题****
+ [错误处理和有问题的消息](best-practices-error-handling.md)
+ [消息重复数据删除和分组](best-practices-message-deduplication.md)
+ [消息处理和定时](best-practices-message-processing.md)

# Amazon SQS 错误处理和有问题的消息
<a name="best-practices-error-handling"></a>

本主题提供有关管理和缓解 Amazon SQS 中的错误的详细说明，包括处理请求错误、捕获有问题的消息以及配置死信队列保留时间以确保消息可靠性的技术。

****主题****
+ [处理 Amazon SQS 中的请求错误](handling-request-errors.md)
+ [捕获 Amazon SQS 中有问题的消息](capturing-problematic-messages.md)
+ [在 Amazon SQS 中设置死信队列保留时间](setting-up-dead-letter-queue-retention.md)

# 处理 Amazon SQS 中的请求错误
<a name="handling-request-errors"></a>

要处理请求错误，请使用下列策略之一：
+ 如果您使用 AWS SDK，则已经有自动*重试和退避逻辑可供*您使用。有关更多信息，请参阅《Amazon Web Services 一般参考》**中的 [AWS中的错误重试和指数回退](https://docs.aws.amazon.com/general/latest/gr/api-retries.html)。
+ 如果您不使用 AWS 软件开发工具包功能进行重试和退避，则在未收到来自 Amazon SQS 的消息、超时或错误消息后，请允许暂停（例如 200 毫秒），然后重试[ReceiveMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ReceiveMessage.html)操作。对于将产生相同结果的 `ReceiveMessage` 的后续使用，应允许更长的暂停时间（例如 400 毫秒）。

# 捕获 Amazon SQS 中有问题的消息
<a name="capturing-problematic-messages"></a>

要捕获所有无法处理的消息并收集准确的 CloudWatch 指标，请配置[死信队列](sqs-dead-letter-queues.md)。
+ 在源队列无法将消息处理指定次数后，重新驱动策略会将消息重定向到死信队列。
+ 使用死信队列将减少消息数并减小向您公开*毒丸*消息（可接收但无法处理的消息）的几率。
+ 在队列中加入毒丸消息可能会给出错误的毒丸消息的年龄，从而扭曲[`ApproximateAgeOfOldestMessage`](sqs-available-cloudwatch-metrics.md) CloudWatch 指标。配置死信队列有助于避免在使用此指标时发出错误警报。

# 在 Amazon SQS 中设置死信队列保留时间
<a name="setting-up-dead-letter-queue-retention"></a>

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

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

# Amazon SQS 消息重复数据删除和分组
<a name="best-practices-message-deduplication"></a>

本主题提供了可确保在 Amazon SQS 中实现一致消息处理的最佳实践，并说明了如何使用：
+ [https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html#API_SendMessage_RequestSyntax](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html#API_SendMessage_RequestSyntax) 防止 FIFO 队列中出现重复消息。
+ [https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html) 管理不同消息组内的消息排序。

****主题****
+ [避免 Amazon SQS 中出现不一致的消息处理](avoiding-inconsistent-message-processing.md)
+ [使用消息重复数据删除 ID](using-messagededuplicationid-property.md)
+ [使用消息组 ID](using-messagegroupid-property.md)
+ [使用接收请求尝试 ID](using-receiverequestattemptid-request-parameter.md)

# 避免 Amazon SQS 中出现不一致的消息处理
<a name="avoiding-inconsistent-message-processing"></a>

由于 Amazon SQS 是一个分布式系统，因此，即使在从 [https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ReceiveMessage.html](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ReceiveMessage.html) API 方法调用成功返回时 Amazon SQS 将消息标记为已发送，使用者也可能不会收到消息。在这种情况下，Amazon SQS 将消息记录为至少已发送一次，即使使用者从未收到过也是如此。由于在这些情况下不会再尝试发送消息，因此我们不建议将[死信队列](sqs-dead-letter-queues.md)的最大接收数量设置为 1。

# 在 Amazon SQS 中使用消息重复数据删除 ID
<a name="using-messagededuplicationid-property"></a>

[https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html) 是一种令牌，仅用于防止在 Amazon SQS FIFO 队列中重复传递消息。它可以确保在 5 分钟的重复数据删除时段内，仅处理和传送具有相同重复数据删除 ID 的消息的一个实例。

如果 Amazon SQS 已接受具有特定重复数据删除 ID 的消息，则任何具有相同 ID 的后续消息都将被确认，但不会传送给使用者。

**注意**  
即使消息已被接收并删除，Amazon SQS 仍会继续跟踪重复数据删除 ID。

**Topics**
+ [在 Amazon SQS 中提供消息重复数据删除 ID](providing-message-deduplication-id.md)
+ [在 Amazon SQS 为单个创建者/使用者系统启用重复数据删除](single-producer-single-consumer.md)
+ [Amazon SQS 中的中断恢复场景](designing-for-outage-recovery-scenarios.md)
+ [在 Amazon SQS 中配置可见性超时](working-with-visibility-timeouts.md)

# 在 Amazon SQS 中提供消息重复数据删除 ID
<a name="providing-message-deduplication-id"></a>

创建者应在以下场景中指定消息重复数据删除 ID：
+ 发送相同消息正文但必须将其视为唯一项时。
+ 发送内容相同但消息属性不同的消息时，确保对每条消息进行独立处理。
+ 发送内容不同（例如消息正文包含重试计数器）但要求 Amazon SQS 将其识别为重复项的消息时。

# 在 Amazon SQS 为单个创建者/使用者系统启用重复数据删除
<a name="single-producer-single-consumer"></a>

如果您有单一的创建者和单一的使用者，且消息因包含特定于应用程序的消息 ID 而具有唯一性，请遵循以下最佳实践：
+ 为队列启用基于内容的重复数据删除（每条消息都具有唯一的正文）。创建者可忽略消息重复数据删除 ID。
+ 如果您为 Amazon SQS FIFO 队列启用了基于内容的重复数据删除，并且发送了具有重复数据删除 ID 的消息，则 [https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html) 重复数据删除 ID 将覆盖生成的基于内容的重复数据删除 ID。
+ 尽管使用者无需为每个请求提供接收请求尝试 ID，但最好提供，因为这样可以更快地执行失败-重试序列。
+ 请求不会干扰消息在 FIFO 队列中的顺序，因此可重试发送或接收请求。

# Amazon SQS 中的中断恢复场景
<a name="designing-for-outage-recovery-scenarios"></a>

FIFO 队列中的重复数据删除过程具有时效性。在设计应用程序时，请确保创建者和使用者均可在客户端或网络中断时恢复运行，而不会引入重复数据或出现处理失败。

创建者注意事项
+ Amazon SQS 强制执行 5 分钟的重复数据删除时段。
+ 如果创建者在 5 分钟后重试 [https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html) 请求，Amazon SQS 会将其视为新消息，这可能导致消息重复。

使用者注意事项
+ 如果使用者未能在可见性超时结束前处理消息，其他使用者可能会接收并处理该消息，从而导致重复处理。
+ 根据应用程序的处理时间调整可见性超时。
+ 使用 [https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ChangeMessageVisibility.html](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ChangeMessageVisibility.html) API 在消息仍在处理时延长超时。
+ 如果消息反复处理失败，请将其路由至[死信队列（DLQ）](sqs-dead-letter-queues.md)，而不是允许无限期地对其进行重新处理。
+ 创建者必须了解队列的重复数据删除间隔。Amazon SQS 的重复数据删除间隔为 5 分钟。在重复数据删除时间间隔过期后重试 `SendMessage` 请求可能会将重复的消息引入队列中。例如，车辆中的移动设备将发送其顺序很重要的消息。如果车辆在接收确认前一段时间失去手机网络连接，则在重新获得手机网络连接之前重试请求可能产生重复项。
+ 使用者必须具有可见性超时，以便将在可见性超时过期之前无法处理消息的风险降至最低。您可通过调用 `ChangeMessageVisibility` 操作延长处理消息时的可见性超时。但是，如果可见性超时过期，其他使用者可立即开始处理消息，从而导致多次处理消息。要避免这种情况，请配置[死信队列](sqs-dead-letter-queues.md)。

# 在 Amazon SQS 中配置可见性超时
<a name="working-with-visibility-timeouts"></a>

为确保可靠的消息处理，请将可见性超时设置为比 AWS SDK 读取超时长。这一设置适用于使用 [https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ReceiveMessage.html](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ReceiveMessage.html) API 进行短轮询和长轮询的情况。较长的可见性超时可防止消息在原始请求完成之前提供给其他使用者，从而降低重复处理的风险。

# 结合使用消息组 ID 和 Amazon SQS FIFO 队列
<a name="using-messagegroupid-property"></a>

在 FIFO（先进先出）队列中，[https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html) 是一个将消息组织成不同组的属性。同一消息组内的消息始终按照严格的顺序逐条处理，从而确保同一组内绝不会有两条消息同时被处理。在标准队列中，使用 `MessageGroupId` 启用[公平队列](sqs-fair-queues.md)。如果需要严格排序，请使用 FIFO 队列。

**Topics**
+ [在 Amazon SQS 中交错多个有序消息组](interleaving-multiple-ordered-message-groups.md)
+ [在 Amazon SQS 的多创建者/使用者系统中避免处理重复消息](avoding-processing-duplicates-in-multiple-producer-consumer-system.md)
+ [避免在 Amazon SQS 中出现具有相同消息组 ID 的大量消息积压](avoid-backlog-with-the-same-message-group-id.md)
+ [避免在 Amazon SQS 中的虚拟队列中重复使用相同的消息组 ID](avoiding-reusing-message-group-id-with-virtual-queues.md)

# 在 Amazon SQS 中交错多个有序消息组
<a name="interleaving-multiple-ordered-message-groups"></a>

要在交错一个 FIFO 队列中的多个有序消息组，请为每个组分配一个 [https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html)（例如，不同用户的会话数据）。这可以让多个使用者能够同时从队列中读取消息，同时确保同一组内的消息按顺序处理。

当具有特定 `MessageGroupId` 的消息正在进行处理且不可见时，任何其他使用者均无法处理来自同一组的消息，直至可见性超时结束或消息被删除。

# 在 Amazon SQS 的多创建者/使用者系统中避免处理重复消息
<a name="avoding-processing-duplicates-in-multiple-producer-consumer-system"></a>

在一个高吞吐量、低延迟且消息顺序并非优先事项的系统中，创建者可为每条消息分配唯一的 [https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html)。这可以确保即使在多创建者/多使用者设置中，Amazon SQS FIFO 队列也能消除重复项。虽然这种方法可以防止重复的消息，但无法保证消息的顺序，因为每条消息都被视为自己的独立组。

在任何具有多个创建者和使用者的系统中，都存在重复传递消息的风险。如果使用者未能在可见性超时结束前处理消息，Amazon SQS 会使该消息再次可用，从而导致其他使用者可能会接收该消息。为了缓解这个问题，请确保根据处理时间正确设置消息确认和可见性超时。

# 避免在 Amazon SQS 中出现具有相同消息组 ID 的大量消息积压
<a name="avoid-backlog-with-the-same-message-group-id"></a>

FIFO 队列最多支持 12 万条传输中消息（使用者已接收但尚未删除的消息）。如果达到此上限，Amazon SQS 不会返回错误，但处理可能会受到影响。您可以联系 [AWS Support](https://docs.aws.amazon.com/awssupport/latest/user/create-service-quota-increase.html) 申请提高此上限。

FIFO 队列会浏览前 12 万条消息，以确定可用的消息组。如果单个消息组中积压了大量消息，则在积压消息处理完毕之前，其他组后续发送的消息将持续被阻止。

**注意**  
当使用者反复多次处理失败时，就可能会导致消息积压。这可能是由于消息内容问题或使用者端故障所致。为防止消息处理延迟，请配置[死信队列](sqs-dead-letter-queues.md)，用于在多次处理失败后转移未处理的消息。这样可以确保同一消息组中的其他消息得到处理，从而避免系统出现瓶颈。

# 避免在 Amazon SQS 中的虚拟队列中重复使用相同的消息组 ID
<a name="avoiding-reusing-message-group-id-with-virtual-queues"></a>

将虚拟队列与共享主机队列一起使用时，请避免在不同的虚拟队列中重复使用相同的 [https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html)。如果多个虚拟队列共享同一主机队列且包含具有相同 `MessageGroupId` 的消息，这些消息可能会相互阻塞，以至阻碍高效处理。为确保顺利处理消息，请为不同虚拟队列中的消息分配唯一的 `MessageGroupId` 值。

# 使用 Amazon SQS 接收请求尝试 ID
<a name="using-receiverequestattemptid-request-parameter"></a>

接收请求尝试 ID 是 Amazon SQS 中用于删除 [https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ReceiveMessage.html](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ReceiveMessage.html) 重复调用的唯一令牌。当您的应用程序与 Amazon SQS 之间出现网络中断或连接问题时，最佳实践是：
+ 在调用 `ReceiveMessage` 时提供接收请求尝试 ID。
+ 如果操作失败，请使用相同的接收请求尝试 ID 重试。

# Amazon SQS 消息处理和定时
<a name="best-practices-message-processing"></a>

本主题提供了有关优化 Amazon SQS 中消息处理速度和效率的全面指导，包括及时处理消息、选择最佳轮询模式以及配置长轮询以提高性能的策略。

****主题****
+ [在 Amazon SQS 中及时处理消息](best-practices-processing-messages-timely-manner.md)
+ [在 Amazon SQS 中设置长轮询](best-practices-setting-up-long-polling.md)
+ [在 Amazon SQS 中使用合适的轮询模式](best-practices-using-appropriate-polling-mode.md)

# 在 Amazon SQS 中及时处理消息
<a name="best-practices-processing-messages-timely-manner"></a>

可见性超时设置取决于您的应用程序需要多长时间来处理和删除消息。例如，如果您的应用程序处理一条消息需要花费 10 秒，并且您将可见性超时设置为 15 分钟，则在上一次处理尝试失败的情况下，您必须等待一个相对较长的时间才能再次尝试处理消息。或者，如果您的应用程序处理一条消息需要花费 10 秒，但您将可见性超时仅设置为 2 秒，则当原始使用者仍在处理消息时，另一个使用者会收到重复消息。

要确保有足够的时间处理消息，请使用下列策略之一：
+ 如果您知道（或者可以合理地估计）处理消息所需的时间，则将消息的*可见性超时* 延长至处理消息所需的最长时间并删除消息。有关更多信息，请参阅[配置可见性超时](sqs-visibility-timeout.md#configuring-visibility-timeout)。
+ 如果您不知道处理消息需要多长时间，请为您的使用者流程创建*检测信号*：指定初始可见性超时（例如 2 分钟），然后（只要您的使用者仍在处理该消息），就可以每分钟将可见性超时延长 2 分钟。
**重要**  
最大可见性超时为从 Amazon SQS 收到 `ReceiveMessage` 请求时起 12 小时。延长可见性超时不会重置 12 小时的最大值。  
此外，您可能无法将单个消息的超时时间设置为 `ReceiveMessage` 请求启动计时器后的整整 12 小时（即 43200 秒）。例如，如果您收到一条消息，并立即通过发送 `ChangeMessageVisibility` 调用，将 `VisibilityTimeout` 设置为 43200 秒，以设置 12 小时的最大值，则该消息很可能会失败。但是，除非通过 `ReceiveMessage` 请求消息和更新可见性超时之间存在明显的延迟，否则使用 43195 秒这个值会起到作用。如果您的使用者需要超过 12 小时，请考虑使用 Step Functions。

# 在 Amazon SQS 中设置长轮询
<a name="best-practices-setting-up-long-polling"></a>

当 `[ReceiveMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ReceiveMessage.html)` API 操作的等待时间大于 0 时，*长轮询*生效。最长长轮询等待时间为 20 秒。长轮询通过减少空响应（当`ReceiveMessage`请求没有消息可用时）和虚假空响应（当消息可用但未包含在响应中时）的数量来帮助降低使用 Amazon SQS 的成本。有关更多信息，请参阅 [Amazon SQS 短轮询和长轮询](sqs-short-and-long-polling.md)。

要确保最佳消息处理，请使用以下策略：
+ 在大多数情况下，您可以将 `ReceiveMessage` 等待时间设置为 20 秒。如果 20 秒对您的应用程序来说太长，则可设置较短的 `ReceiveMessage` 等待时间（最少 1 秒）。如果您不使用 AWS 软件开发工具包来访问 Amazon SQS，或者将 AWS 软件开发工具包配置为缩短等待时间，则可能需要修改您的 Amazon SQS 客户端，以允许更长的请求或使用更短的等待时间进行长时间轮询。
+ 如果您对多个队列实施长轮询，则对每个队列使用一个线程，而不是对所有队列使用单个线程。如果对每个队列使用一个线程，您的应用程序将能够在各队列中的消息可用时处理这些消息；如果使用单个线程来轮询多个队列，则可能导致应用程序在等待（最长 20 秒）没有任何可用消息的队列时无法处理其他队列中的可用消息。

**重要**  
为避免 HTTP 错误，请确保 `ReceiveMessage` 请求的 HTTP 响应超时比 `WaitTimeSeconds` 参数更长。有关更多信息，请参阅 [ReceiveMessage](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_ReceiveMessage.html)。

# 在 Amazon SQS 中使用合适的轮询模式
<a name="best-practices-using-appropriate-polling-mode"></a>
+ 长轮询使您能够在消息可用后立即从 Amazon SQS 队列中使用消息。
  + 要降低使用 Amazon SQS 的成本并减少空队列的空接收次数（对不返回任何消息的 `ReceiveMessage` 操作的响应次数），请启用长轮询。有关更多新信息，请参阅 [Amazon SQS 长轮询](sqs-short-and-long-polling.md)。
  + 要提高轮询具有多次接收的多个线程的效率，请减少线程数。
  + 在大多数情况下，长轮询优于短轮询。
+ 短轮询会立即返回响应，即使轮询的 Amazon SQS 队列为空。
  + 要满足应立即响应 `ReceiveMessage` 请求的应用程序的要求，请使用短轮询。
  + 短轮询的计费与长轮询相同。