

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

# 重试行为
<a name="feature-retry-behavior"></a>

**重要**  
此页面上描述的行为需要选择加入，直到它成为默认行为。`AWS_NEW_RETRIES_2026=true`在您的环境中设置。如果没有此设置，您的 SDK 将使用 2026 年之前的重试行为，这在退避时间、重试配额成本和特定于服务的默认值方面有所不同。有关详细信息，请参阅公[告博客文章](https://aws.amazon.com/blogs/developer/announcing-updated-retry-behavior-for-aws-sdks-and-tools/)。

当对的请求因暂时性错误或限制而 AWS 服务 失败时，SDK 可以自动重试该请求。本页介绍如何配置重试及其内部工作方式。
+ [配置重试次数](#configuring-retries)：选择重试模式，设置最大尝试次数，并了解配置优先级。
+ [重试的工作原理](#how-retries-work): 重试流程、错误分类、退避公式、重试配额机制和特定于服务的行为。

## 配置重试次数
<a name="configuring-retries"></a>

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

### 选择重试模式
<a name="choosing-a-retry-mode"></a>

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


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

#### 标准模式（默认）
<a name="standard-mode"></a>

标准模式使用带抖动的指数退避重试失败的请求。它对瞬态错误（例如网络超时）使用较短的延迟，对限制错误（例如）使用更长的延迟。`ThrottlingException`

标准模式包括**重试配额**，一个令牌桶，用于每次重试时扣除令牌，并在请求成功时补充令牌。当可用令牌用完时，SDK 会在不重试的情况下返回错误，因此您的应用程序会快速失败，而不是等待不太可能成功的重试。这还可以减少重试流量，从而帮助更快地解决服务中断问题。在正常操作期间，配额保持已满且无效。重试配额永远不会延迟或阻止初始请求。只有重试次数会受到影响。有关更多信息，请参阅 [重试配额（令牌桶）](#retry-quota-token-bucket)。

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

#### 自适应模式
<a name="adaptive-mode"></a>

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

速率限制器按照 SDK 客户端实例运行。来自客户端的所有请求都具有相同的速率限制，无论它们针对哪个 API 操作或资源。

**何时使用自适应模式：**
+ 您的客户端以单个资源（例如，一个 DynamoDB 表）为目标，并且您希望频繁出现限制响应。这在自动工作流程、批处理器或大批量调用单个 API 操作的 AI 工作负载中很常见。
+ 您希望 SDK 在服务发出限制信号时自动减速。

**何时不使用自适应模式：**
+ 您的客户端向多个资源发送请求或为多个租户提供服务。限制一个资源会导致速率限制器减慢来自该客户端的所有请求，包括对未受影响的资源的请求。
+ 初始请求需要可预测的延迟。

不建议将自适应模式作为常规默认模式。

#### 传统模式
<a name="legacy-mode"></a>

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

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

**可用版本：**Java、Python、Ruby、PHP、C\+\+、CLI

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

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

### 重试设置
<a name="retry-settings"></a>

以下设置控制重试行为。你可以通过[环境变量](environment-variables.md)、[共享配置文件](file-format.md) (`~/.aws/config`) 或代码中的客户端配置来设置它们。


| 设置 | 它控制什么 | 环境变量 | Config 文件密钥 | 默认 | 
| --- | --- | --- | --- | --- | 
| 重试模式 | 使用哪种重试策略 | AWS\_RETRY\_MODE | retry\_mode | standard | 
| 最大尝试次数 | 包括初始请求在内的总尝试次数 | AWS\_MAX\_ATTEMPTS | max\_attempts | 3（参见备注） | 

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

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

### 配置优先级
<a name="configuration-precedence"></a>

当您在多个位置指定相同的设置时，SDK 会使用以下优先顺序（从高到低）来解析该值：

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

1. **[环境变量](environment-variables.md)。**例如，`AWS_RETRY_MODE` 或 `AWS_MAX_ATTEMPTS`。

1. **[共享配置文件](file-format.md)。**`retry_mode`或`max_attempts`键入`~/.aws/config`。

1. **SDK 默认。**该设置的内置默认值。

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

### Language-specific 配置
<a name="language-specific-configuration"></a>

本页面（`retry_mode`和`max_attempts`）中描述的跨SDK设置适用于所有软件开发工具包。但是，在代码中配置重试的 API 因语言而异。有关特定语言的配置选项，例如自定义退避策略、其他可重试错误和重试配额调整，请参阅您的 SDK 开发者指南。

## 重试的工作原理
<a name="how-retries-work"></a>

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

### 请求失败时会发生什么
<a name="what-happens-when-a-request-fails"></a>

当您通过 SDK 进行 API 调用时， AWS SDK 将遵循以下顺序：

1. **仅限[自适应模式](#adaptive-mode)：**SDK 会检查客户端速率限制器。如果检测到限制，SDK 可能会在发送请求之前延迟或阻止请求。

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

1. 如果服务返回成功响应，SDK 会将结果返回到您的代码中。

1. *如果请求失败，SDK 会将错误分类为*暂时*错误、*限制*错误或不可重试错误。*请参阅[哪些错误会被重试](#which-errors-are-retried)。

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

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

1. 软件开发工具包会检查[重试配额（令牌桶）](#retry-quota-token-bucket). 如果代币预算耗尽，SDK 不会重试，而是将错误返回到您的代码中。例外：对于[Long-polling 操作](#long-polling-operations)，SDK 在返回错误之前仍会应用退避延迟。

1. SDK 根据错误类型和重试尝试次数计算退避延迟。请参阅[SDK 要等多久](#how-long-does-the-sdk-wait)。

1. SDK 等待计算出的延迟，然后从步骤 2 开始再次发送请求。

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

### 哪些错误会被重试
<a name="which-errors-are-retried"></a>

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

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

#### 错误分类
<a name="error-classification"></a>

使用较短的基准延迟（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`）会立即返回到您的代码中。

**注意**  
带有限制错误代码的 HTTP 5XX 被归类为限制错误，而不是暂时错误，即使 5XX 错误通常是暂时性的。SDK 首先匹配错误代码，然后回退到 HTTP 状态码。

限制错误意味着服务由于速率限制而主动拒绝了您的请求，因此 SDK 会等待更长的时间才能重试，让服务有时间恢复容量。[SDK 要等多久](#how-long-does-the-sdk-wait)有关具体延迟，请参阅。

### SDK 要等多久
<a name="how-long-does-the-sdk-wait"></a>

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

#### 按错误类型划分的基本延迟
<a name="base-delays-by-error-type"></a>

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


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

#### 退避公式
<a name="backoff-formula"></a>

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 秒。

#### 行之有效的例子
<a name="worked-examples"></a>

**示例 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 ms 时，上限之前的计算延迟为：


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

对于暂时性错误，上限在第 10 次重试（第 11 次尝试）时生效。对于基准为 1,000 ms 的节流错误，上限将在第 6 次重试时生效。

**注意**  
默认情况下，最大尝试次数为 3 次（1 次初始请求 \+ 2 次重试），则永远不会达到退避上限。下表说明了如果增加幅度远`max_attempts`远超过默认值会发生什么。

#### 为什么抖动很重要
<a name="why-jitter-matters"></a>

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

例如，假设 1,000 个客户同时收到 503。完全抖动会将他们的第一次重试次数均匀分布在 50 毫秒的时间段内，而不是将所有 1,000 次重试次数均匀分布在 50 毫秒。

#### Server-directed 重试时机
<a name="server-directed-retry-timing"></a>

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

### 重试配额（令牌桶）
<a name="retry-quota-token-bucket"></a>

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

#### 重试配额的工作原理
<a name="how-the-retry-quota-works"></a>

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


| 参数 | 值 | 
| --- | --- | 
| 预算容量 | 500 个代币 | 
| 每次暂时（非限制）重试的成本 | 14 个代币 | 
| 每次重试限制的费用 | 5 个代币 | 
| 重试后成功恢复令牌 | 上次重试消耗量（14 或 5） | 
| 成功恢复令牌无需重试 | 1 个代币 | 

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

#### 配额何时会阻止重试
<a name="when-does-the-quota-block-retries"></a>

重试配额会随时跟踪代币，但只有在预算耗尽时才会阻止重试。在正常运行期间，几乎所有请求都会成功，并且预算仍然满额。配额对重试没有明显的影响。

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

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

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

#### 实际影响
<a name="practical-implications"></a>
+ **故障率低：**配额无效。预算保持在或接近容纳能力。
+ **服务中断期间：**如果您的请求中有很大一部分持续失败，则配额将耗尽，您的客户端会立即返回错误，而不是等待重试。这可以减少客户端延迟，释放线程和连接，并帮助服务更快地恢复。
+ **恢复：**当服务恢复并且请求再次开始成功时，成功的重试会恢复其全部代币消耗，首次尝试成功将恢复 1 个令牌。预算会逐渐充满，重试会自动恢复。
+ **范围：**代币预算通常限于单个 SDK 客户端实例。具体范围可能因 SDK 而异。它不在进程或主机之间共享。

### Service-specific 行为
<a name="service-specific-behavior"></a>

#### DynamoDB
<a name="dynamodb"></a>

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


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

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

#### Long-polling 操作
<a name="long-polling-operations"></a>

某些 AWS 操作使用长轮询。他们可以保持连接处于打开状态，等待工作到达。这些操作会受到特殊的重试处理：
+ `SQS.ReceiveMessage`
+ `SFN.GetActivityTask`
+ `SWF.PollForActivityTask`
+ `SWF.PollForDecisionTask`

**特殊行为：**当重试配额耗尽且重试被阻止（中的第 7 步[请求失败时会发生什么](#what-happens-when-a-request-fails)）时，SDK 在将错误返回到您的代码之前仍会应用退避延迟。

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

## Support by AWS SDK 和工具
<a name="feature-retry-behavior-sdk-compat"></a>

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


| SDK | 支持 | GitHub 追踪问题 | 
| --- | --- | --- | 
| [适用于 Java 2.x 的 SDK](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/) | 是 | [追踪问题](https://github.com/aws/aws-sdk-java-v2/discussions/6984) | 
| [适用于 Python (Boto3) 的 SDK](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html) | 是 | [追踪问题](https://github.com/boto/boto3/discussions/4789) | 
| [适用于.NET 4.x 的 SDK](https://docs.aws.amazon.com/sdk-for-net/latest/developer-guide/) | 是 | [追踪问题](https://github.com/aws/aws-sdk-net/issues/4411) | 
| [适用于 PowerShell V5 的工具](https://docs.aws.amazon.com/powershell/latest/userguide/) | 是 | [追踪问题](https://github.com/aws/aws-tools-for-powershell/issues/418) | 
| [适用于 JavaScript 3.x 的软件开发工具包](https://docs.aws.amazon.com/sdk-for-javascript/latest/developer-guide/) | 是 | [追踪问题](https://github.com/aws/aws-sdk-js-v3/issues/8037) | 
| [适用于 PHP 3.x 的 SDK](https://docs.aws.amazon.com/sdk-for-php/latest/developer-guide/) | 是 | [追踪问题](https://github.com/aws/aws-sdk-php/discussions/3285) | 
| [适用于 Kotlin 的 SDK](https://docs.aws.amazon.com/sdk-for-kotlin/latest/developer-guide/) | 是 | [追踪问题](https://github.com/aws/aws-sdk-kotlin/discussions/1885) | 
| [适用于 Rust 的 SDK](https://docs.aws.amazon.com/sdk-for-rust/latest/dg/) | 是 | [追踪问题](https://github.com/awslabs/aws-sdk-rust/discussions/1431) | 
| [适用于 Swift 的 SDK](https://docs.aws.amazon.com/sdk-for-swift/latest/developer-guide/) | 查看追踪问题 | [追踪问题](https://github.com/awslabs/aws-sdk-swift/discussions/2166) | 
| [适用于 Ruby 3.x 的 SDK](https://docs.aws.amazon.com/sdk-for-ruby/latest/developer-guide/) | 查看追踪问题 | [追踪问题](https://github.com/aws/aws-sdk-ruby/discussions/3390) | 
| [适用于 Go V2 (1.x) 的 SDK](https://docs.aws.amazon.com/sdk-for-go/v2/developer-guide/) | 查看追踪问题 | [追踪问题](https://github.com/aws/aws-sdk-go-v2/issues/3416) | 
| [适用于 C\+\+ 的 SDK](https://docs.aws.amazon.com/sdk-for-cpp/latest/developer-guide/) | 查看追踪问题 | [追踪问题](https://github.com/aws/aws-sdk-cpp/issues/3832) | 
| [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/) v2 | 查看追踪问题 | [追踪问题](https://github.com/aws/aws-cli/discussions/10329) | 