View a markdown version of this page

重试行为 - AWS 软件开发工具包和工具

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

重试行为

重要

此页面上描述的行为需要选择加入,直到它成为默认行为。AWS_NEW_RETRIES_2026=true在您的环境中设置。如果没有此设置,您的 SDK 将使用 2026 年之前的重试行为,这种行为在退避时间、重试配额成本和特定服务的默认值上有所不同。有关详细信息,请参阅公告博客文章。

当向的请求由于暂时性错误或限制而 AWS 服务 失败时,SDK 可以自动重试该请求。本页介绍如何配置重试及其内部工作方式。

  • 配置重试:选择重试模式,设置最大尝试次数,了解配置优先级。

  • 重试的工作原理:重试流程、错误分类、退避公式、重试配额机制和特定服务行为。

配置重试

您可以控制 SDK 使用哪种重试策略以及重试次数。

选择重试模式

重试模式决定了请求失败时 SDK 的行为。有三种模式可供选择:标准模式、自适应模式和传统模式。

标准 自适应 Legacy
重试配额 支持 是 因 SDK 而异
可以延迟初始请求 否 是 否
Error-type-specific 退缩 支持 是 因 SDK 而异
跨软件开发工具包实现标准化 支持 是 否
建议 所有工作负载的默认值 Single-resource,节流密集,耐延迟 仅向后兼容

标准模式(默认)

标准模式使用带抖动的指数退避重试失败的请求。它对瞬态错误(例如网络超时)使用较短的延迟,对节流错误(例如)使用较长的延迟。ThrottlingException

标准模式包括重试配额、每次重试扣除代币并在请求成功时补充代币的代币存储桶。当可用令牌用尽时,SDK 会在不重试的情况下返回错误,因此您的应用程序会快速失败,而不是等待不太可能成功的重试。这还可以通过减少重试流量来帮助更快地解决服务中断问题。在正常运行期间,配额将保持满状态,没有任何效果。重试配额永远不会延迟或阻止初始请求。只有重试会受到影响。有关更多信息,请参阅 重试配额(代币存储桶)。

除非您有特定理由选择其他模式,否则请使用标准模式。

自适应模式

自适应模式包括标准模式下的所有内容,外加客户端速率限制器。速率限制器跟踪限制响应并调整 SDK 发送请求的速率。与标准模式不同,当检测到限制时,自适应模式可以延迟或阻止初始请求,而不仅仅是重试。

速率限制器针对每个 SDK 客户端实例运行。来自客户端的所有请求共享相同的速率限制,无论它们针对的是哪个 API 操作或资源。

何时使用自适应模式:

  • 您的客户端以单个资源(例如,一个 DynamoDB 表)为目标,您预计会频繁出现限制响应。这在自动化工作流程、批处理器或大量调用单个 API 操作的人工智能工作负载中很常见。

  • 您希望 SDK 在服务信号限制时自动减速。

何时不使用自适应模式:

  • 您的客户向多个资源发送请求或为多个租户提供服务。对一个资源进行限制会导致速率限制器减慢来自该客户端的所有请求,包括对未受影响资源的请求。

  • 您需要在初始请求上提供可预测的延迟。

不建议将自适应模式作为一般默认模式。

传统模式

传统模式是每个 SDK 在引入标准模式之前使用的重试行为。它不包括标准化的重试配额。一些 SDK(例如 Java)在传统模式下有自己的重试配额实现,但各个 SDK 的行为并不一致。如果没有标准配额,在服务中断期间,客户端会继续以全额费率重试。这会占用不太可能成功的请求的线程和连接,同时会增加负载,从而延迟服务恢复。

传统模式因 SDK 而异。重试次数、退避时间、可重试错误集和限制行为因语言而异。在软件开发工具包之间移动时,依赖于传统重试行为的代码可能会有所不同。

可用于:Java、Python、Ruby、PHP、C++、CLI

不适用于:.NET、Go、Kotlin、Rust、Swift、 JavaScript

旧模式的存在是为了向后兼容。如果您当前使用传统模式,请切换到标准模式。

重试设置

以下设置控制重试行为。您可以通过环境变量、共享配置文件 (~/.aws/config) 或代码中的客户端配置来设置它们。

设置 它控制什么 环境变量 配置文件密钥 默认
重试模式 使用哪种重试策略 AWS_RETRY_MODE retry_mode standard
最大尝试次数 包括初始请求在内的总尝试次数 AWS_MAX_ATTEMPTS max_attempts 3(见注释)

最大尝试次数值为3表示 SDK 发出一个初始请求和最多两次重试。设置最大尝试次数1以完全禁用重试。

注意

DynamoDB 和 DynamoDB Streams 客户端默认为最大尝试次数。4这些服务使用较短的基本退避延迟(25 毫秒而不是 50 毫秒)来匹配其低延迟特性。额外的尝试使上次重试的最大退避值与其他服务相当。您可以使用上表中显示的相同设置来覆盖此设置。

配置优先级

当您在多个位置指定相同的设置时,SDK 使用以下优先级从高到低解析该值:

  1. 代码中明确的客户端配置。直接在 SDK 客户端或其配置对象上设置的值。

  2. 环境变量。例如,AWS_RETRY_MODE 或 AWS_MAX_ATTEMPTS。

  3. 共享配置文件。retry_mode或max_attempts键入~/.aws/config。

  4. 默认 SDK。该设置的内置默认值。

这遵循标准 AWS SDK 配置优先级。在较高级别设置的值总是覆盖在较低级别上设置的值。例如,如果您将环境变量设置AWS_RETRY_MODE=adaptive为环境变量~/.aws/config,retry_mode=standard则 SDK 将使用自适应模式。

Language-specific 配置

本页(retry_mode和max_attempts)中描述的跨 SDK 设置适用于所有 SDK。但是,用于在代码中配置重试的 API 因语言而异。有关特定语言的配置选项,例如自定义退避策略、其他可重试错误和重试配额调整,请参阅 SDK 的开发人员指南。

重试的工作原理

本节介绍了 AWS SDK 如何处理失败的请求:哪些错误会触发重试、SDK 在两次尝试之间等待多长时间以及何时停止重试。

请求失败时会发生什么

当您通过 AWS SDK 进行 API 调用时,开发工具包遵循以下顺序:

  1. 自适应模式仅限自适应模式:SDK 检查客户端速率限制器。如果检测到节流,SDK 可能会在发送请求之前延迟或阻止请求。

  2. SDK 将请求发送到 AWS 服务 终端节点。

  3. 如果服务返回成功的响应,SDK 会将结果返回给您的代码。

  4. 如果请求失败,SDK 会将错误归类为暂时性错误、限制错误或不可重试错误。 请参阅重试哪些错误。

  5. 如果错误不可重试,SDK 会立即将错误返回到您的代码中。未尝试重试。

  6. 如果错误是可重试的,SDK 会检查其是否已达到最大尝试次数。如果是,它会将错误返回到您的代码中。

  7. SDK 会检查重试配额(代币存储桶). 如果代币预算耗尽,SDK 不会重试并将错误返回到您的代码中。例外:对于Long-polling 运营,SDK 在返回错误之前仍会应用退避延迟。

  8. SDK 根据错误类型和重试次数计算退避延迟。请参阅SDK 需要等待多长时间。

  9. SDK 等待计算出的延迟,然后从第 2 步再次发送请求。

SDK 会重复此循环,直到请求成功、达到最大尝试次数、重试配额用尽或出现不可重试的错误。整个过程是自动的。您的应用程序看到的要么是成功的响应,要么是最终的错误。

重试哪些错误

SDK 将每个失败的请求分为三类之一:临时请求、限制请求或不可重试。此分类决定了 SDK 是否重试请求以及等待多长时间才能重试。

分类基于服务响应中的错误代码和 HTTP 状态码。例如,带有错误代码RequestTimeout的 HTTP 400 被归类为临时性并重试。带有ValidationException的 HTTP 400 被归类为不可重试并立即返回。

错误分类

以较短的基本延迟 (50 ms) 重试瞬态错误:

错误代码
RequestTimeout
RequestTimeoutException
InternalError
IDPCommunicationError
I/O 失败(连接重置、DNS 解析失败、套接字超时)
(任何没有识别错误代码的 HTTP 500、502、503 或 504)

重试限制错误时会延迟时间更长(1,000 ms):

错误代码
Throttling
ThrottlingException
ThrottledException
RequestThrottledException
TooManyRequestsException
ProvisionedThroughputExceededException
TransactionInProgressException
LimitExceededException
PriorRequestNotComplete
RequestThrottled
EC2ThrottledException
RequestLimitExceeded
SlowDown
BandwidthLimitExceeded

Non-retryable 错误(例如AccessDeniedException、ValidationException、ResourceNotFoundException)会立即返回到您的代码中。

注意

尽管 5XX 错误通常是暂时性的,但带有限制错误代码的 HTTP 5XX 仍被归类为限制错误,而不是暂时性错误。SDK 首先匹配错误代码,然后回退到 HTTP 状态码。

限制错误意味着该服务由于速率限制主动拒绝了您的请求,因此,SDK 会等待更长的时间才能重试,让服务有时间恢复容量。SDK 需要等待多长时间有关具体延迟,请参见。

SDK 需要等待多长时间

SDK 使用指数退避和完全抖动。平均而言,每次重试的等待时间都比上次更长,采用随机分配以分散来自多个客户端的请求。

按错误类型划分的基本延迟

基本延迟取决于错误是瞬态的还是节流的:

错误类型 基本延迟 理由
瞬态(非节流) 50 毫秒 瞬态错误通常会在几毫秒内解决。较短的基本延迟可实现快速恢复。
节流 1,000 毫秒 该服务对请求进行了速率限制。较长的基本延迟可以有时间恢复容量。

退避公式

SDK 使用以下公式计算每次重试延迟:

delay = random(0, 1) × min(20,000 ms, base_delay × 2^retry)

其中:

  • random(0, 1)返回 0 到 1 之间的均匀分布值

  • base_delay瞬态错误为 50 毫秒,节流错误为 1,000 毫秒

  • retry第一次重试(第二次整体请求尝试)从 0 开始

最大退避上限为 20 秒。无论尝试了多少次,单个延迟都不会超过 20 秒。

成功的例子

示例 1:暂时性错误,最多 3 次尝试

步骤 发生了什么 Delay
尝试 1 初始请求。服务返回 HTTP 503。 (无)
尝试 2 SDK 随机等待(0, 50 毫秒)。使用 503 重试失败。 0—50 毫秒(平均约 25 毫秒)
尝试 3 SDK 随机等待(0, 100 毫秒)。重试成功。 0—100 毫秒(平均约 50 毫秒)

两次重试的总延迟平均约为 75 毫秒。

示例 2:限制错误,最多 3 次尝试

步骤 发生了什么 Delay
尝试 1 初始请求。服务返回 429 Throttling。 (无)
尝试 2 SDK 随机等待(0, 1,000 毫秒)。重试返回 429。 0—1,000 毫秒(平均约 500 毫秒)
尝试 3 SDK 随机等待(0, 2,000 毫秒)。重试成功。 0—2,000 毫秒(平均约 1,000 毫秒)

两次重试的总延迟平均约为 1,500 毫秒。

示例 3:瞬态错误,触及退避上限

如果基本延迟为 50 毫秒,则上限之前的计算延迟为:

重试尝试 计算出的最大延迟 20 秒后上限
1 50 毫秒 50 毫秒
2 100 毫秒 100 毫秒
5 800 毫秒 800 毫秒
9 12,800 毫秒 12,800 毫秒
10 25,600 毫秒 20,000 毫秒

对于暂时性错误,上限在第 10 次重试(第 11 次尝试)时生效。对于基数为 1,000 ms 的节流错误,上限在第 6 次重试时生效。

注意

默认最大尝试次数为 3 次(1 次初始请求 + 2 次重试),则永远不会达到退避上限。下表说明了如果增加幅度远max_attempts远超过默认值会发生什么。

为什么抖动很重要

随机乘数称为完全抖动。没有它,所有同时遇到错误的客户端都会同时重试,从而造成大量的重试流量(“雷鸣般的群体” 问题)。完全抖动会将重试次数均匀地分布在整个退避窗口中,因此该服务会收到稳定的请求流,而不是同步的峰值。

例如,假设 1,000 个客户端都同时收到 503。Full jitter 会在 50 毫秒的窗口内均匀分配第一次重试,而不是让所有 1,000 次重试都在 50 毫秒时完成。

Server-directed 重试时间

有些在错误响应中 AWS 服务 包含x-amz-retry-after标题。标头值是以毫秒为单位的延迟。当此标头存在时,SDK 使用服务器指定的延迟,限制为计算出的退避延迟的最小值和计算出的退避延迟的最大值加 5,000 毫秒。由于计算出的退避本身上限为 20 秒,因此服务器定向的有效最大延迟为 25 秒。SDK 不对该值应用抖动,因为服务预计会抖动该值。这使该服务能够准确地在预期可用容量时进行通信。

重试配额(代币存储桶)

SDK 维持内部代币预算,用于跟踪成功请求与失败的比率。当故障普遍发生时,预算就会耗尽,SDK 会直接返回错误。您的应用程序会快速失败,而不是等待不太可能成功的重试。这也减少了重试流量,有助于更快地解决服务中断问题。

重试配额的运作方式

代币预算已满额开始。每次重试都会扣除代币。当重试成功时,SDK 会恢复该重试消耗的令牌。当请求在第一次尝试成功时(无需重试),SDK 会恢复 1 个令牌。当预算达到零时,SDK 会停止重试并将错误直接返回到您的代码。

参数 值
预算容量 500 个代币
每次瞬态(非节流)重试的成本 14 个代币
每次限制重试的成本 5 个代币
重试后成功恢复代币 上次重试(14 或 5)消耗的量
成功恢复代币无需重试 1 个代币

瞬态重试的成本较高反映了它们不同的失败模式。像 500 这样的瞬态错误和连接失败通常表示存在服务范围的问题。在这种情况下,继续重试不太可能成功。它会增加您的通话延迟,占用客户资源,并可能延迟每个人的恢复。限制错误表明服务需要更多时间才能成功请求。SDK 在两次重试之间等待更长的时间以提高成功的可能性。

配额区块何时重试

重试配额可随时跟踪代币,但仅在预算耗尽时阻止重试。在正常运行期间,几乎所有请求都会成功,并且预算保持满负荷状态。配额对重试没有明显的影响。

成功的重试仅会恢复其自身的代币成本(14 或 5 个令牌),而不会恢复同一请求中先前失败的重试成本。例如,如果第一次重试失败而第二次重试成功,则预算净损失14个代币。当重试用尽所有尝试都没有成功时,预算消耗得最快,但是当请求需要多次重试才能成功时,预算也会逐渐耗尽。

默认情况下,最大尝试次数为 3 次,当超过大约 22% 的请求导致持续的暂时性故障,或超过大约 32% 的限制错误时,配额开始耗尽。低于这些费率,成功的请求补充预算的速度要比失败的重试耗尽预算的速度快。

预算的起始余额为500个代币,为吸收短暂的失败提供了缓冲区。短暂的错误激增,即使是严重的错误,也不会阻止重试,除非错误持续足够长的时间以耗尽缓冲区。

实际影响

  • 失败率低:配额没有影响。预算保持在或接近容量。

  • 服务中断期间:如果您的请求中有很大一部分持续失败,则配额将耗尽,您的客户端会立即恢复错误,而不是等待重试。这样可以减少客户端延迟,释放线程和连接,并帮助服务更快地恢复。

  • 恢复:当服务恢复和请求再次开始成功时,成功的重试将恢复其全部令牌成本,首次尝试成功恢复1个令牌。预算逐渐充值,重试自动恢复。

  • 范围:代币预算通常限于单个 SDK 客户端实例。确切的范围可能因 SDK 而异。它不在进程或主机之间共享。

Service-specific 行为

DynamoDB

DynamoDB 客户端使用针对 DynamoDB 的低延迟配置文件进行了优化的调整默认值:

设置 一般默认 DynamoDB 默认
瞬态(非节流)基本延迟 50 毫秒 25 毫秒
限制基本延迟 1,000 毫秒 1,000 毫秒
最大尝试次数 3 4

这些默认值适用于亚马逊 DynamoDB 和 DynamoDB Streams。

Long-polling 运营

某些 AWS 操作使用长轮询。他们可以保持连接处于打开状态,等待工作到来。这些操作会受到特殊的重试处理:

  • SQS.ReceiveMessage

  • SFN.GetActivityTask

  • SWF.PollForActivityTask

  • SWF.PollForDecisionTask

特殊行为:当重试配额用尽且重试被阻止(中的第 7 步请求失败时会发生什么)时,SDK 在将错误返回到您的代码之前仍会应用退避延迟。

这很重要,因为长轮询操作通常在紧密循环中调用。您的代码调用ReceiveMessage,处理任何消息,然后立即ReceiveMessage再次调用。如果不强制退缩,代币预算耗尽将导致 SDK 毫不拖延地返回错误。然后,您的轮询循环将立即发送下一个请求,从而增加客户端 CPU 使用率并产生额外的流量。强制退避延迟打破了这个周期,使客户机资源使用量和轮询率在故障期间保持在可控范围内。

支持者 AWS SDK 和工具

下表列出了每个 SDK 中更新的重试行为的可用性。有关最低版本、前后默认值和代码示例等 SDK-specific 详细信息,请参阅 GitHub 跟踪问题。