

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

# 以编程方式访问 Amazon EC2
<a name="ec2-api-intro"></a>

您可以使用 AWS 管理控制台 或编程接口来创建和管理 Amazon EC2 资源。关于使用 Amazon EC2 控制台的相关信息，请参阅[《Amazon EC2 用户指南》](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/)。

**工作方式**
+ [Amazon EC2 端点](ec2-endpoints.md)
+ [最终一致性](eventual-consistency.md)。
+ [幂等性](ec2-api-idempotency.md)
+ [请求节流](ec2-api-throttling.md)
+ [分页](ec2-api-pagination.md)

**编程接口**
+ [AWS Command Line Interface (AWS CLI)](ec2-aws-cli.md)
+ [AWS CloudFormation](ec2-cloudformation.md)
+ [AWS SDK](sdk-general-information-section.md)
+ [低级别 API](ec2-low-level-api.md)

**入门**
+ [代码示例](service_code_examples.md)
+ [Console-to-Code](console-to-code.md)

**监控**
+ [AWS CloudTrail](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/monitor-with-cloudtrail.html)
+ [监控请求](monitor.md)

# Amazon EC2 服务端点
<a name="ec2-endpoints"></a>

端点是用作 AWS Web 服务入口点的 URL。Amazon EC2 支持以下端点类型：
+ [IPv4 端点](#ipv4)
+ [双栈端点](#ipv6)（同时支持 IPv4 和 IPv6）
+ [FIPS 端点](https://docs.aws.amazon.com/general/latest/gr/rande.html#FIPS-endpoints)

当您发出请求时，您可以指定要使用的端点。如果您未指定终端节点，则默认使用该 IPv4 终端节点。要使用不同的端点类型，您必须在请求中指定。有关如何执行此操作的示例，请参阅[指定端点](#examples)。有关可用端点的列表，请参阅[各区域的服务端点](#service-endpoints)。

## IPv4 端点
<a name="ipv4"></a>

IPv4 端点仅支持 IPv4 流量。 IPv4 终端节点适用于所有区域。

如果您指定通用端点 `ec2.amazonaws.com`，则我们将端点用于 `us-east-1`。要使用其他区域，请指定其关联端点。例如，如果您指定 `ec2.us-east-2.amazonaws.com` 为端点，我们会将您的请求定向到 `us-east-2` 端点。

IPv4 端点名称使用以下命名约定：
+ `service.region.amazonaws.com`

例如，该`eu-west-1`区域的 IPv4 终端节点名称为`ec2.eu-west-1.amazonaws.com`。

## 双栈（IPv4 和 IPv6）端点
<a name="ipv6"></a>

双栈端点同时支持 IPv4 和 IPv6 流量。当您向双栈终端节点发出请求时，终端节点 URL 会解析为 IPv6 或 IPv4 地址，具体取决于您的网络和客户端使用的协议。

Amazon EC2 仅支持区域性的双堆栈端点，这意味着您必须在端点名称中指定所使用的区域。双堆栈端点名称使用以下命名约定：
+ `ec2.region.api.aws`

例如，`eu-west-1` 区域的双堆栈端点名称是 `ec2.eu-west-1.api.aws`。

## 各区域的服务端点
<a name="service-endpoints"></a>

以下是 Amazon EC2 的服务端点。有关区域的更多信息，请参阅《Amazon EC2 用户指南》**中的[区域和可用区](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html)。

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/ec2/latest/devguide/ec2-endpoints.html)

## 指定端点
<a name="examples"></a>

本节提供了一些在发出请求时如何指定端点的示例。

------
#### [ AWS CLI ]

以下示例显示在使用 AWS CLI时，如何为 `us-east-2` 区域指定端点。
+ **双堆栈**

  ```
  aws ec2 describe-regions --region us-east-2 --endpoint-url https://ec2.us-east-2.api.aws
  ```
+ **IPv4**

  ```
  aws ec2 describe-regions --region us-east-2 --endpoint-url https://ec2.us-east-2.amazonaws.com
  ```

------
#### [ AWS SDK for Java 2.x ]

以下示例显示在使用 AWS SDK for Java 2.x时，如何为 `us-east-2` 区域指定端点。
+ **双堆栈**

  ```
  Ec2Client client = Ec2Client.builder()
      .region(Region.US_EAST_2)
      .endpointOverride(URI.create("https://ec2.us-east-2.api.aws"))
      .build();
  ```
+ **IPv4**

  ```
  Ec2Client client = Ec2Client.builder()
      .region(Region.US_EAST_2)
      .endpointOverride(URI.create("https://ec2.us-east-2.amazonaws.com"))
      .build();
  ```

------
#### [ 适用于 Java 的 AWS SDK 1.x ]

以下示例说明如何使用 适用于 Java 的 AWS SDK 1.x 为该`eu-west-1`区域指定终端节点。
+ **双堆栈**

  ```
  AmazonEC2 s3 = AmazonEC2ClientBuilder.standard()
       .withEndpointConfiguration(new EndpointConfiguration(
            "https://ec2.eu-west-1.api.aws",
            "eu-west-1"))
       .build();
  ```
+ **IPv4**

  ```
  AmazonEC2 s3 = AmazonEC2ClientBuilder.standard()
       .withEndpointConfiguration(new EndpointConfiguration(
            "https://ec2.eu-west-1.amazonaws.com",
            "eu-west-1"))
       .build();
  ```

------
#### [ AWS SDK for Go ]

以下示例显示在使用 适用于 Go 的 AWS SDK时，如何为 `us-east-1` 区域指定端点。
+ **双堆栈**

  ```
  sess := session.Must(session.NewSession())
  svc := ec2.New(sess, &aws.Config{
      Region: aws.String(endpoints.UsEast1RegionID),
      Endpoint: aws.String("https://ec2.us-east-1.api.aws")
  })
  ```
+ **IPv4**

  ```
  sess := session.Must(session.NewSession())
  svc := ec2.New(sess, &aws.Config{
      Region: aws.String(endpoints.UsEast1RegionID),
      Endpoint: aws.String("https://ec2.us-east-1.amazonaws.com")
  })
  ```

------

# 亚马逊 EC2 API 的最终一致性
<a name="eventual-consistency"></a>

由于支持 Amazon EC2 API 的系统的分布式特性，Amazon API 遵循最终一致性模型。这意味着，您运行的影响您的 Amazon EC2 资源的 API 命令的结果可能不会立即显示给您随后运行的所有命令。在执行紧随上一个 API 命令的 API 命令时，应记住这一点。

最终一致性会影响您管理资源的方式。例如，如果您运行命令创建了某个资源，这个资源最终会对其他命令变得可见。这意味着，如果您立刻运行命令去修改或查询刚创建的资源，由于其 ID 可能尚未在系统中传播完成，您可能会收到资源不存在的错误。

要管理最终一致性，您可以执行以下操作：
+ 在运行修改命令之前，先确认资源的当前状态。使用指数回退算法运行相应的 `Describe` 命令，来确保有足够的时间让前一个命令传播遍整个系统。为此，请重复运行该`Describe`命令，从几秒钟的等待时间开始，然后逐渐增加到几分钟的等待时间。
+ 增加后续命令之间的等待时间，即使 `Describe` 命令返回准确的响应，也是如此。应用指数退避算法，从几秒钟的等待时间开始，然后逐渐增加到几分钟的等待时间。

**最终一致性错误示例**  
以下是一些由于最终一致性而可能遇到的错误代码示例。
+ `InvalidInstanceID.NotFound`

  如果您成功执行了 `RunInstances` 命令，然后立刻使用 `RunInstances` 返回的实例 ID 执行另一个命令，可能会返回 `InvalidInstanceID.NotFound` 错误。这并不代表该实例不存在。

  以下是可能受影响的一些具体命令：
  + `DescribeInstances`：要确认实例的实际状态，请使用指数回退算法运行此命令。
  + `TerminateInstances`：要确认实例状态，请先使用指数回退算法运行 `DescribeInstances` 命令。
**重要**  
如果您在运行 `TerminateInstances` 之后收到 `InvalidInstanceID.NotFound` 错误，这并不代表实例已经或即将被终止。实例仍有可能正在运行。因此，您应当首先使用 `DescribeInstances` 来确认实例状态。
+ `InvalidGroup.NotFound`

  如果您成功执行了 `CreateSecurityGroup` 命令，然后立即使用 `CreateSecurityGroup` 返回的安全组 ID 执行另一个命令，可能会返回 `InvalidGroup.NotFound` 错误。要确认安全组的状态，请使用指数回退算法运行 `DescribeSecurityGroups` 命令。
+ `InstanceLimitExceeded`

  您请求的实例数量超过了当前对指定实例类型的配额上限。如果您在短时间内频繁创建和终止实例，可能会出乎意料地触及此配额限制，因为即使实例已被终止，它们在一段时间内仍会计入您的实例配额。

# Ensuring idempotency in Amazon EC2 API requests
<a name="ec2-api-idempotency"></a>

当您发出变更 API 请求时，该请求通常会在操作的异步工作流完成之前返回结果。即使请求已经返回结果，操作在完成之前也可能会超时或遇到其他服务器问题。这样就很难确定请求是否成功，并且会导致进行多次重试以确保操作成功完成。但是，如果原始请求和后续重试成功，则会多次完成操作。这意味着您可能会创建超过预期数量的资源。

*幂等性*确保 API 请求完成不超过一次。对于幂等性请求，如果原始请求成功完成，则后续重试也会成功完成，而不会执行任何后续操作。不过，结果中可能包含更新后的信息，例如当前的创建状态。

**Topics**
+ [Amazon EC2 中的幂等性](#client-tokens)
+ [RunInstances 的幂等性](#run-instances-idempotency)
+ [示例](#Run_Instance_Idempotency_CLI)
+ [针对幂等请求的重试建议](#recommended-actions)

## Amazon EC2 中的幂等性
<a name="client-tokens"></a>

以下 API 操作默认具备幂等性，无需额外配置。对应的 AWS CLI 命令也默认支持幂等性。

**默认具备幂等性的操作**
+ AssociateAddress
+ CreateVpnConnection
+ DisassociateAddress
+ ReplaceNetworkAclAssociation
+ TerminateInstances

以下 API 操作通过*客户端令牌*来支持幂等性（可选）。对应的 AWS CLI 命令同样支持通过客户端令牌实现幂等性。客户端令牌是一个由最多 64 个 ASCII 字符组成、区分大小写的唯一字符串。要让这些操作的 API 请求具备幂等性，请在请求中指定一个客户端令牌。您不应将同一个客户端令牌用于其他 API 请求。如果您使用相同的客户端令牌并保持所有参数一致来重试一个已成功完成的请求，该重试会直接成功，而不会执行任何额外操作。如果您在重试成功的请求时使用了相同的客户端令牌，但一个或多个参数发生变化（区域或可用区除外），重试将失败，并返回 `IdempotentParameterMismatch` 错误。

**使用客户端令牌实现幂等性的操作**
+ AllocateHosts
+ AllocateIpamPoolCidr
+ AssociateClientVpnTargetNetwork
+ AssociateIpamResourceDiscovery
+ AttachVerifiedAccessTrustProvider
+ AuthorizeClientVpnIngress
+ CopyFpgaImage
+ CopyImage
+ CreateCapacityReservation
+ CreateCapacityReservationFleet
+ CreateClientVpnEndpoint
+ CreateClientVpnRoute
+ CreateEgressOnlyInternetGateway
+ CreateFleet
+ CreateFlowLogs
+ CreateFpgaImage
+ CreateInstanceConnectEndpoint
+ CreateIpam
+ CreateIpamPool
+ CreateIpamResourceDiscovery
+ CreateIpamScope
+ CreateLaunchTemplate
+ CreateLaunchTemplateVersion
+ CreateManagedPrefixList
+ CreateNatGateway
+ CreateNetworkAcl
+ CreateNetworkInsightsAccessScope
+ CreateNetworkInsightsPath
+ CreateNetworkInterface
+ CreateReplaceRootVolumeTask
+ CreateReservedInstancesListing
+ CreateRouteTable
+ CreateTrafficMirrorFilter
+ CreateTrafficMirrorFilterRule
+ CreateTrafficMirrorSession
+ CreateTrafficMirrorTarget
+ CreateVerifiedAccessEndpoint
+ CreateVerifiedAccessGroup
+ CreateVerifiedAccessInstance
+ CreateVerifiedAccessTrustProvider
+ CreateVolume
+ CreateVpcEndpoint
+ CreateVpcEndpointConnectionNotification
+ CreateVpcEndpointServiceConfiguration
+ DeleteVerifiedAccessEndpoint
+ DeleteVerifiedAccessGroup
+ DeleteVerifiedAccessInstance
+ DeleteVerifiedAccessTrustProvider
+ DetachVerifiedAccessTrustProvider
+ ExportImage
+ ImportImage
+ ImportSnapshot
+ ModifyInstanceCreditSpecification
+ ModifyLaunchTemplate
+ ModifyReservedInstances
+ ModifyVerifiedAccessEndpoint
+ ModifyVerifiedAccessEndpointPolicy
+ ModifyVerifiedAccessGroup
+ ModifyVerifiedAccessGroupPolicy
+ ModifyVerifiedAccessInstance
+ ModifyVerifiedAccessInstanceLoggingConfiguration
+ ModifyVerifiedAccessTrustProvider
+ ProvisionIpamPoolCidr
+ PurchaseHostReservation
+ RequestSpotFleet
+ RequestSpotInstances
+ RunInstances
+ StartNetworkInsightsAccessScopeAnalysis
+ StartNetworkInsightsAnalysis

**幂等性类型**
+ 区域级 –请求在每个区域内具备幂等性。然而，您可以在其他区域中使用同一个请求（包括相同的客户端令牌）。
+ 可用区级 – 请求在一个区域内的每个可用区中具备幂等性。例如，如果您在同一区域内的两次 **AllocateHosts** 调用中使用相同的客户端令牌，只要它们的 **AvailabilityZone** 参数值不同，这两个调用都会成功。

## RunInstances 的幂等性
<a name="run-instances-idempotency"></a>

[RunInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RunInstances.html) API 操作同时采用区域级和可用区级幂等性。

具体采用哪种幂等性，取决于您在 RunInstances API 请求中如何指定可用区。在以下情况中，请求会使用**可用区级幂等性**：
+ 您在 **Placement** 数据类型中，通过 **AvailabilityZone** 参数显式指定了可用区
+ 您使用 **SubnetId 参数**隐式指定了可用区

您既没有显式也没有隐式指定可用区，则请求会使用**区域级幂等性**。

### 可用区级幂等性
<a name="zonal-idempotency"></a>

可用区级幂等性确保 RunInstances API 请求在同一区域内的每个可用区中都是幂等的。这保证了在同一区域内，使用相同客户端令牌的请求在每个可用区中只能成功执行一次。然而，您仍然可以使用同一个客户端令牌在该区域的其他可用区中启动实例。

例如，如果您发送一个在 `us-east-1a` 可用区启动实例的幂等请求，然后在 `us-east-1b` 可用区再次使用相同的客户端令牌发起请求，我们会在这些可用区中分别启动实例。如果后续重试中的一个或多个参数发生变化，那么在这些可用区内使用相同客户端令牌进行的重试要么会成功返回但不执行任何操作，要么会因参数不匹配而报告 `IdempotentParameterMismatch` 错误。

### 区域级幂等性
<a name="regional-idempotency"></a>

区域级幂等性确保 RunInstances API 请求在同一区域内是幂等的。这保证了在同一区域内，使用相同客户端令牌的请求只能成功执行一次。然而，您可以使用完全相同的请求（包括相同的客户端令牌）在其他区域中启动实例。

例如，如果您发送一个在 `us-east-1` 区域启动实例的幂等请求，然后在 `eu-west-1` 区域中再次使用相同的客户端令牌发起请求，我们会在两个区域中分别启动实例。如果后续重试中的一个或多个参数发生变化，那么在这些区域内使用相同客户端令牌进行的重试要么会成功返回但不执行任何操作，要么会因参数不匹配而报告 `IdempotentParameterMismatch` 错误。

**提示**  
如果请求的区域中有某个可用区不可用，使用区域级幂等性的 RunInstances 请求可能会失败。为了充分利用 AWS 基础设施提供的可用区功能，我们建议在启动实例时使用可用区级幂等性。即使请求的区域中另一个可用区不可用，只要目标可用区可用，使用可用区级幂等性的 RunInstances 请求仍然会成功。

## 示例
<a name="Run_Instance_Idempotency_CLI"></a>

### AWS CLI 命令示例
<a name="cli-example"></a>

要使 AWS CLI 命令具备幂等性，请添加 `--client-token` 选项。

**示例 1：幂等性**  
以下 [allocate-hosts](https://docs.aws.amazon.com/cli/latest/reference/ec2/allocate-hosts.html) 命令通过包含客户端令牌而具备幂等性。

```
aws ec2 allocate-hosts  --instance-type m5.large  --availability-zone eu-west-1a  --auto-placement on  --quantity 1 --client-token 550e8400-e29b-41d4-a716-446655440000
```

**示例 2：run-instances 的区域级幂等性**  
以下 [run-instances](https://docs.aws.amazon.com/cli/latest/reference/ec2/run-instances.html) 命令通过包含客户端令牌而使用区域级幂等性，因为它既没有显式也没有隐式指定可用区。

```
aws ec2 run-instances --image-id ami-b232d0db --count 1 --key-name my-key-pair --client-token 550e8400-e29b-41d4-a716-446655440000
```

**示例 3：run-instances 的可用区级幂等性**  
以下 [run-instances](https://docs.aws.amazon.com/cli/latest/reference/ec2/run-instances.html) 命令通过包含客户端令牌并显式指定可用区而使用可用区级幂等性。

```
aws ec2 run-instances  --placement "AvailabilityZone=us-east-1a" --image-id ami-b232d0db --count 1 --key-name my-key-pair --client-token 550e8400-e29b-41d4-a716-446655440000
```

### API 请求示例
<a name="api-example"></a>

要使 API 请求具有幂等性，请添加 `ClientToken` 参数。

**示例 1：幂等性**  
以下 [AllocateHosts](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_AllocateHosts.html) API 请求通过包含客户端令牌而具备幂等性。

```
https://ec2.amazonaws.com/?Action=AllocateHosts
&AvailabilityZone=us-east-1b
&InstanceType=m5.large
&Quantity=1
&AutoPlacement=off
&ClientToken=550e8400-e29b-41d4-a716-446655440000
&AUTHPARAMS
```

**示例 2：RunInstances 的区域级幂等性**  
以下 [RunInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RunInstances.html) API 请求通过包含客户端令牌而使用区域级幂等性，因为它既没有显式也没有隐式指定可用区。

```
https://ec2.amazonaws.com/?Action=RunInstances
&ImageId=ami-3ac33653
&MaxCount=1
&MinCount=1
&KeyName=my-key-pair
&ClientToken=550e8400-e29b-41d4-a716-446655440000
&AUTHPARAMS
```

**示例 3：RunInstances 的可用区级幂等性**  
以下 [RunInstances](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RunInstances.html) API 请求通过包含客户端令牌并显式指定可用区而使用可用区级幂等性。

```
https://ec2.amazonaws.com/?Action=RunInstances
&Placement.AvailabilityZone=us-east-1d
&ImageId=ami-3ac33653
&MaxCount=1
&MinCount=1
&KeyName=my-key-pair
&ClientToken=550e8400-e29b-41d4-a716-446655440000
&AUTHPARAMS
```

## 针对幂等请求的重试建议
<a name="recommended-actions"></a>

下表显示了幂等性 API 请求可能获得的一些常见响应，并提供了重试建议。


| 响应 | 建议 | 评论 | 
| --- | --- | --- | 
|  200（正常）  |  不重试  |  原始请求成功完成。成功返回任何后续重试。  | 
|  400 系列响应代码（[客户端错误](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/errors-overview.html#CommonErrors)）  |  不重试  |  请求存在问题，原因如下： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/ec2/latest/devguide/ec2-api-idempotency.html) 如果请求涉及正在改变状态的资源，则重试请求可能会成功。  | 
|  500 系列响应代码（[服务器端错误](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/errors-overview.html#api-error-codes-table-server)）  |  重试  |  该错误是由 AWS 服务器端问题引起，通常是暂时性的。使用适当的退避策略重复发出请求。  | 

# 亚马逊 API 的请求限制 EC2
<a name="ec2-api-throttling"></a>

Amazon EC2 会按区域限制每个 AWS 账户的 EC2 API 请求。我们这样做是为了帮助提高服务的性能，并确保所有亚马逊 EC2 买家都能公平使用。限制可确保对 Amazon EC2 API 的请求不超过允许的最大 API 请求限制。无论 API 请求来自以下哪些来源，都会受到请求限制的约束：
+ 第三方应用程序
+ 命令行工具
+ 亚马逊 EC2 控制台

如果您超过 API 节流限制，则会收到 `RequestLimitExceeded` 错误代码。

**Topics**
+ [如何应用节流](#throttling-how)
+ [请求令牌限制](#throttling-limits-rate-based)
+ [资源令牌限制](#throttling-limits-cost-based)
+ [监控 API 节流](#throttling-monitor)
+ [重试和指数回退](#api-backoff)
+ [请求提高限制](#throttling-increase)

## 如何应用节流
<a name="throttling-how"></a>

Amazon EC2 使用[令牌存储桶算法](https://en.wikipedia.org/wiki/Token_bucket)来实现 API 限制。使用此算法，您的账户拥有一个持有特定数量的*令牌*的*存储桶*。存储桶中令牌的数量表示您在任意一秒的节流限制。

Amazon EC2 实施了两种类型的 API 限制：

**Topics**
+ [请求速率限制](#throttling-rate-based)
+ [资源速率限制](#throttling-cost-based)

### 请求速率限制
<a name="throttling-rate-based"></a>

在请求速率限制中，每个 API 都会被单独评估，您的节流限制按每个 API 的请求数量分别计算。您每发起一次请求，就会从该 API 的存储桶中移除一个令牌。例如，*非变异* API 操作的 `DescribeHosts` 的令牌存储桶容量为 100 个令牌。您在一秒内最多可以发起 100 次 `DescribeHosts` 请求。如果在某一秒内超过 100 次请求，您会在该 API 上被节流，剩余请求会失败；但其他 API 的请求不受影响。

存储桶会以设定的速率自动填充。如果存储桶的容量低于其最大容量，则每秒都会向其添加一定数量的令牌，直到其达到最大容量。如果重填令牌到达时存储桶已满，额外的令牌会被丢弃。存储桶中的令牌数量不能超过其最大数量。例如，*非变异* API 操作的 `DescribeHosts` 的令牌存储桶容量为 100 个令牌，重填速率为每秒 20 个令牌。如果您在一秒钟内发起 100 次 `DescribeHosts` 请求，存储桶中的令牌将被消耗至零（0）。之后，存储桶会以每秒 20 个的速度重填令牌，直到重新达到 100 个的最大容量。这意味着，如果期间没有请求，一个空存储桶需要 5 秒才能重新装满。

您无需等存储桶完全填满才能继续发起 API 请求。您可以使用刚添加进存储桶的重填令牌。如果您立即使用重填令牌，存储桶就不会达到最大容量。例如，*非变异* API 操作的 `DescribeHosts` 的令牌存储桶容量为 100 个令牌，重填速率为每秒 20 个令牌。如果您在一秒内用掉存储桶中的全部 100 个令牌，仍可以随后每秒发起 20 次请求，使用的就是不断重填到存储桶中的令牌。只有当您每秒发起的请求少于 20 次时，存储桶才有机会重新填满。

有关更多信息，请参阅 [请求令牌存储桶的容量与重填速率](#throttling-limits-rate-based)。

### 资源速率限制
<a name="throttling-cost-based"></a>

某些 API 操作（例如 `RunInstances` 和 `TerminateInstances`，如下表所示），除了请求速率限制外，还使用资源速率限制。这些 API 会有一个独立的资源令牌存储桶，根据请求影响的资源数量来消耗令牌。与请求令牌存储桶类似，资源令牌存储桶也有一个最大容量用于支持突发请求，同时具备重填速率，使您能够在需要时持续保持稳定的请求速率。如果您超出了某个 API 的资源存储桶限制（包括当存储桶尚未重填到足以支持下一次 API 请求时的情况），即使整体 API 节流限制未达到，您仍会被限制执行该操作。

例如，`RunInstances` 的资源令牌存储桶容量为 1000 个令牌，重填速率为每秒 2 个令牌。因此，您可以使用任意数量的 API 请求立即启动 1000 个实例，例如一次请求启动 1000 个，或者分四次请求，每次启动 250 个实例。在资源令牌存储桶耗尽后，您每秒最多只能启动两个实例，可以是一次请求启动两个，也可以是两次请求各启动一个。

有关更多信息，请参阅 [资源令牌存储桶容量和重填速率](#throttling-limits-cost-based)。

## 请求令牌存储桶的容量与重填速率
<a name="throttling-limits-rate-based"></a>

为实现请求速率限制，API 操作分为以下几类：
+ **非变异操作** – 用于检索资源相关数据的 API 操作。此类别通常包括所有 `Describe*`、`List*`、`Search*` 和 `Get*` API 操作，例如 `DescribeRouteTables`、`SearchTransitGatewayRoutes` 和 `GetIpamPoolCidrs`。这些 API 操作通常具有最高的 API 节流限制。
+ **未筛选、未分页的非变异操作** – 非变异 API 操作中的一个特定子集，如果请求未指定[分页](https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-pagination.html)或[筛选条件](https://docs.aws.amazon.com//AWSEC2/latest/UserGuide/Using_Filtering.html#Filtering_Resources_CLI)，则会从一个较小的令牌存储桶中扣除令牌。建议您在调用这些操作时使用分页和筛选，以便令牌从标准（容量更大）的存储桶中扣除。
+ **变异操作** – 用于创建、修改或删除资源的 API 操作。此类别通常包括所有未归类为*非变异操作*的 API 操作，例如 `AllocateHosts`、`ModifyHosts` 和 `CreateCapacityReservation`。这些操作的节流限制低于非变异 API 操作。
+ **资源密集型操作** – 完成时间最长、消耗资源最多的变异类 API 操作。这些操作的节流限制比*变异操作*更低。它们的节流是独立于其他*变异操作*的。
+ **控制台非变更操作** — 从 Amazon 控制台请求的非变更 API 操作。 EC2 这些 API 操作的节流是独立于其他非变异 API 操作的。
+ **未分类操作** – 这些 API 操作会拥有独立的令牌存储桶容量和重填速率，即便从定义上它们原本属于上述某一类别。


| API 操作类别 | 操作 | 存储桶最大容量 | 存储桶重填速率 | 
| --- | --- | --- | --- | 
| 非变异操作 |  未包含在其他类别中的 `Describe*`、`List*`、`Search*` 和 `Get*` API 操作。  | 100 | 20 | 
| 未筛选、未分页的非变异操作 |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/ec2/latest/devguide/ec2-api-throttling.html)  | 50 | 10 | 
| 变异操作 | 所有不是*资源密集型操作*或*未分类操作*的变异 API 操作。 | 50 | 5 | 
| 资源密集型操作 |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/ec2/latest/devguide/ec2-api-throttling.html)  | 50 | 5 | 
| 控制台非变异操作 |  `Describe*`、`List*``Search*`、和 `Get*` API 操作，由亚马逊 EC2 控制台调用，但未包含在其他类别中。  | 100 | 10 | <a name="uncategorized"></a>


| 未分类操作 | 存储桶最大容量 | 存储桶重填速率 | 
| --- | --- | --- | 
| AcceptVpcEndpointConnections | 10 | 1 | 
| AdvertiseByoipCidr | 1 | 0.1 | 
| AssignIpv6Addresses | 100 | 5 | 
| AssignPrivateIpAddresses | 100 | 5 | 
| AssignPrivateNatGatewayAddress | 10 | 1 | 
| AssociateCapacityReservationBillingOwner | 1 | 0.5 | 
| AssociateEnclaveCertificateIamRole | 10 | 1 | 
| AssociateIamInstanceProfile | 100 | 5 | 
| AssociateNatGatewayAddress | 10 | 1 | 
| AttachVerifiedAccessTrustProvider | 10 | 2 | 
| AuthorizeClientVpnIngress | 5 | 2 | 
| CancelDeclarativePoliciesReport | 1 | 1 | 
| CopyImage | 100 | 1 | 
| CreateClientVpnRoute | 5 | 2 | 
| CreateCoipCidr | 5 | 1 | 
| CreateCoipPool | 5 | 1 | 
| CreateDefaultSubnet | 1 | 1 | 
| CreateDefaultVpc | 1 | 1 | 
| CreateLaunchTemplateVersion | 100 | 5 | 
| CreateNatGateway | 10 | 1 | 
| CreateNetworkInterface | 100 | 5 | 
| CreateRestoreImageTask | 50 | 0.1 | 
| CreateSnapshot | 100 | 5 | 
| CreateSnapshots | 100 | 5 | 
| CreateSpotDatafeedSubscription | 50 | 3 | 
| CreateStoreImageTask | 50 | 0.1 | 
| CreateSubnetCidrReservation | 5 | 1 | 
| CreateTags | 100 | 10 | 
| CreateVerifiedAccessEndpoint | 20 | 4 | 
| CreateVerifiedAccessGroup | 10 | 2 | 
| CreateVerifiedAccessInstance | 10 | 2 | 
| CreateVerifiedAccessTrustProvider | 10 | 2 | 
| CreateVolume | 100 | 5 | 
| CreateVpcEndpoint | 4 | 0.3 | 
| CreateVpcEndpointServiceConfiguration | 10 | 1 | 
| DeleteClientVpnRoute | 5 | 2 | 
| DeleteCoipCidr | 5 | 1 | 
| DeleteCoipPool | 5 | 1 | 
| DeleteCoipPoolPermission | 5 | 1 | 
| DeleteNatGateway | 10 | 1 | 
| DeleteNetworkInterface | 100 | 5 | 
| DeleteSnapshot | 100 | 5 | 
| DeleteSpotDatafeedSubscription | 50 | 3 | 
| DeleteSubnetCidrReservation | 5 | 1 | 
| DeleteQueuedReservedInstances | 5 | 5 | 
| DeleteTags | 100 | 10 | 
| DeleteVerifiedAccessEndpoint | 20 | 4 | 
| DeleteVerifiedAccessGroup | 10 | 2 | 
| DeleteVerifiedAccessInstance | 10 | 2 | 
| DeleteVerifiedAccessTrustProvider | 10 | 2 | 
| DeleteVolume | 100 | 5 | 
| DeleteVpcEndpoints | 4 | 0.3 | 
| DeleteVpcEndpointServiceConfigurations | 10 | 1 | 
| DeprovisionByoipCidr | 1 | 0.1 | 
| DeregisterImage | 100 | 5 | 
| DescribeAggregateIdFormat | 10 | 10 | 
| DescribeByoipCidrs | 1 | 0.5 | 
| DescribeCapacityBlockExtensionOfferings | 10 | 0.15 | 
| DescribeCapacityBlockOfferings | 10 | 0.15 | 
| DescribeDeclarativePoliciesReports | 5 | 5 | 
| DescribeHostReservations | 5 | 2 | 
| DescribeHostReservationOfferings | 5 | 2 | 
| DescribeIdentityIdFormat | 10 | 10 | 
| DescribeIdFormat | 10 | 10 | 
| DescribeInstanceTopology | 1 | 1 | 
| DescribeMovingAddresses | 1 | 1 | 
| DescribePrincipalIdFormat | 10 | 10 | 
| DescribeReservedInstancesOfferings | 10 | 10 | 
| DescribeSecurityGroupReferences | 20 | 5 | 
| DescribeSpotDatafeedSubscription | 100 | 13 | 
| DescribeSpotFleetInstances | 100 | 5 | 
| DescribeSpotFleetRequestHistory | 100 | 5 | 
| DescribeSpotFleetRequests | 50 | 3 | 
| DescribeStaleSecurityGroups | 20 | 5 | 
| DescribeStoreImageTasks | 50 | 0.5 | 
| DescribeVerifiedAccessInstanceLoggingConfigurations | 10 | 2 | 
| DetachVerifiedAccessTrustProvider | 10 | 2 | 
| DisableFastLaunch | 5 | 2 | 
| DisableImageBlockPublicAccess | 1 | 0.1 | 
| DisableSnapshotBlockPublicAccess | 1 | 0.1 | 
| DisassociateCapacityReservationBillingOwner | 1 | 0.5 | 
| DisassociateEnclaveCertificateIamRole | 10 | 1 | 
| DisassociateIamInstanceProfile | 100 | 5 | 
| DisassociateNatGatewayAddress | 10 | 1 | 
| EnableFastLaunch | 5 | 2 | 
| EnableImageBlockPublicAccess | 1 | 0.1 | 
| EnableSnapshotBlockPublicAccess | 1 | 0.1 | 
| GetAssociatedEnclaveCertificateIamRoles | 10 | 1 | 
| GetDeclarativePoliciesReportSummary | 5 | 5 | 
| GetHostReservationPurchasePreview | 5 | 2 | 
| ModifyImageAttribute | 100 | 5 | 
| ModifyInstanceMetadataDefaults | 2 | 2 | 
| ModifyInstanceMetadataOptions | 100 | 5 | 
| ModifyLaunchTemplate | 100 | 5 | 
| ModifyNetworkInterfaceAttribute | 100 | 5 | 
| ModifySnapshotAttribute | 100 | 5 | 
| ModifyVerifiedAccessEndpoint | 20 | 4 | 
| ModifyVerifiedAccessEndpointPolicy | 20 | 4 | 
| ModifyVerifiedAccessGroup | 10 | 2 | 
| ModifyVerifiedAccessGroupPolicy | 20 | 4 | 
| ModifyVerifiedAccessInstance | 10 | 2 | 
| ModifyVerifiedAccessInstanceLoggingConfiguration | 10 | 2 | 
| ModifyVerifiedAccessTrustProvider | 10 | 2 | 
| ModifyVpcEndpoint | 4 | 0.3 | 
| ModifyVpcEndpointServiceConfiguration | 10 | 1 | 
| MoveAddressToVpc | 1 | 1 | 
| ProvisionByoipCidr | 1 | 0.1 | 
| PurchaseCapacityBlock | 10 | 0.15 | 
| PurchaseCapacityBlockExtension | 10 | 0.15 | 
| PurchaseHostReservation | 5 | 2 | 
| PurchaseReservedInstancesOffering | 5 | 5 | 
| RejectVpcEndpointConnections | 10 | 1 | 
| RestoreAddressToClassic | 1 | 1 | 
| RevokeClientVpnIngress | 5 | 2 | 
| RunInstances | 5 | 2 | 
| StartDeclarativePoliciesReport | 1 | 1 | 
| StartInstances | 5 | 2 | 
| TerminateInstances | 100 | 5 | 
| UnassignPrivateIpAddresses | 100 | 5 | 
| UnassignPrivateNatGatewayAddress | 10 | 1 | 
| WithdrawByoipCidr | 1 | 0.1 | 

## 资源令牌存储桶容量和重填速率
<a name="throttling-limits-cost-based"></a>

下表列出了使用资源速率限制的 API 操作所对应的资源令牌存储桶容量及其重填速率。


| API 操作 | 存储桶最大容量 | 存储桶重填速率 | 
| --- | --- | --- | 
| RunInstances | 1000 | 2 | 
| TerminateInstances | 1000 | 20 | 
| StartInstances | 1000 | 2 | 
| StopInstances | 1000 | 20 | 

## 监控 API 节流
<a name="throttling-monitor"></a>

您可以使用亚马逊 CloudWatch 来监控您的亚马逊 EC2 API 请求，并收集和跟踪有关 API 限制的指标。您还可以创建警报，在接近达到 API 节流限制时向您发出警告。有关更多信息，请参阅 [使用亚马逊监控亚马逊 EC2 API 请求 CloudWatch使用监控 API 请求 CloudWatch](monitor.md)。

## 重试和指数回退
<a name="api-backoff"></a>

您的应用程序可能需要重试某个 API 请求。例如：
+ 检查资源状态是否更新
+ 枚举大量资源（例如，您的所有卷）
+ 在请求因服务端错误（5xx）或节流错误而失败时执行重试

但如果是客户端错误（4xx），您必须先修正请求中的问题，再进行重试。

**资源状态更改**  
在开始轮询检查状态更新之前，应先预留足够时间让请求可能完成。例如，等待几分钟，然后再检查实例是否处于活动状态。当开始轮询时，应在连续请求之间设置合理的睡眠间隔，以降低 API 请求速率。为了获得最佳的效果，请使用递增或可变的睡眠间隔。

或者，您可以使用 Amazon EventBridge 通知您某些资源的状态。例如，您可以使用**EC2 实例状态更改通知**事件来通知您实例的状态变化。有关更多信息，请参阅[ EC2 使用自动化 Amazon EventBridge](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/automating_with_eventbridge.html)。

**重试**  
当您需要轮询或重试 API 请求时，我们建议使用指数回退算法来计算请求之间的睡眠间隔。指数回退的原理是对于连续错误响应，重试等待间隔越来越长。您应该实施最长延迟间隔和最大重试次数。您还可以使用抖动（随机延迟）来避免请求持续冲突。有关更多信息，请参阅[超时、重试和回退并抖动](https://aws.amazon.com/builders-library/timeouts-retries-and-backoff-with-jitter/)。

每个 AWS SDK 都实现了自动重试逻辑。有关更多信息，请参阅《工具参考指南》*AWS SDKs 和《工具参考指南*》中的[重试行为](https://docs.aws.amazon.com/sdkref/latest/guide/feature-retry-behavior.html)。

## 请求提高限制
<a name="throttling-increase"></a>

您可以请求增加您的 AWS 账户的 API 节流限制。

**建议**
+ 单次请求的限制最多不应超过您当前限制的三倍。
+ 优先请求提升存储桶的重填速率，再考虑提升存储桶的最大容量。
+ 如果您请求的重填速率会超过当前的存储桶最大容量，则应同时请求提升最大容量。
+ 提供所有需要提升限制的 API 操作。限制是应用在单个 API 操作上的，而不是应用在整个 API 操作类别上。
+ 以下 API 操作拥有请求速率限制和资源速率限制：`RunInstances`、`StartInstances`、`StopInstances` 和 `TerminateInstances`。务必说明您希望提升的是哪一种限制。

**请求访问此功能**

1. 打开 [AWS 支持 中心](https://console.aws.amazon.com/support/home#/)。

1. 选择**创建工单**。

1. 选择**账户和账单**。

1. 对于**服务**，选择**一般信息和入门**。

1. 在 **“类别”** 中，选择 “**使用 AWS 和服务**”。

1. 选择**下一步：其他信息**。

1. 对于 **Subject (主题)**，请输入 **Request an increase in my Amazon EC2 API throttling limits**。

1. 对于**描述**，复制以下模板并提供所需信息。

   ```
   Please increase the API throttling limits for my account. 
   Related page: https://docs.aws.amazon.com/ec2/latest/devguide/ec2-api-throttling.html
   Description: Brief notes about your use case. If available, include the IDs
       of a few Amazon EC2 requests that were throttled.
   Time window: One-hour window when peak throttling or usage occurred.
   region_1 request rate increases:
       action: new_bucket_maximum_capacity
       action: new_bucket_refill_rate
       action: new_bucket_maximum_capacity|new_bucket_refill_rate
   region_1 resource rate increases:
       action: new_bucket_maximum_capacity
       action: new_bucket_refill_rate
       action: new_bucket_maximum_capacity|new_bucket_refill_rate
   region_2 request rate increases:
       action: new_bucket_maximum_capacity
       action: new_bucket_refill_rate
       action: new_bucket_maximum_capacity|new_bucket_refill_rate
   region_2 resource rate increases:
       action: new_bucket_maximum_capacity
       action: new_bucket_refill_rate
       action: new_bucket_maximum_capacity|new_bucket_refill_rate
   ```

1. 选择**下一步：立即解决或联系我们**。

1. 在**联系我们**选项卡上，选择您的首选联系语言和首选联系方式。

1. 选择**提交**。

# Amazon EC2 API 中的分页
<a name="ec2-api-pagination"></a>

我们建议在调用可能返回大量结果的描述类操作（例如 `DescribeInstances`）时使用分页。使用分页可以限制每次描述调用返回的项目数量，并控制调用返回所需的时间。如果您拥有大量资源，未分页的调用可能会被限制速率，甚至可能超时。因此，相比未分页调用，分页调用通常更稳定成功，从而带来更好的整体延迟表现。

有关更多信息，请参阅《Amazon EC2 API 参考**》中的[分页](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/Query-Requests.html#api-pagination)。

## 最佳实践
<a name="pagination-best-practices"></a>

在可能的情况下，在描述调用中指定资源 ID 列表。这是描述大量资源的最快捷方式。请注意，单次调用中不应指定超过 1000 个 ID。示例如下：

```
private List<Reservation> describeMyInstances(List<String> ids){
    if (ids == null || ids.isEmpty()) {
        return ImmutableList.of();
    }
        
    final DescribeInstancesRequest request = new DescribeInstancesRequest()
            .withInstanceIds(ids);

    return ec2.describeInstances(request).getReservations();
}
```

如果您无法在描述调用中指定资源 ID，我们强烈建议使用分页。示例如下：

```
private List<Reservation> describeMyInstances(final Collection<Filter> filters){
    final DescribeInstancesRequest request = new DescribeInstancesRequest()
            .withFilters(filters)
            .withMaxResults(1000);

    List<Reservation> reservations = new ArrayList<>();
    String nextToken = null;
    do {
        request.setNextToken(nextToken);
        final DescribeInstancesResult response = ec2.describeInstances(request);
        reservations.addAll(response.getReservations());
        nextToken = response.getNextToken();
    } while (nextToken != null);

    return reservations;
}
```

如果需要重试分页调用，请使用[带抖动的指数退避算法](ec2-api-throttling.md#api-backoff)。

## 常见问题
<a name="pagination-common-issues"></a>

以下是一些无意间发起未分页调用的代码示例。

**Example 问题示例：传递一个空的资源 ID 列表**  
下面的代码使用了 ID 列表。然而，如果该列表为空，最终会导致发起未分页的调用。  

```
private List<Reservation> describeMyInstances(List<String> ids){
    final DescribeInstancesRequest request = new DescribeInstancesRequest()
            .withInstanceIds(ids);

    return ec2.describeInstances(request).getReservations();
}
```
要修正此问题，请确保在执行描述调用之前列表不为空。  

```
private List<Reservation> describeMyInstances(List<String> ids){
    if (ids == null || ids.isEmpty()) {
        return ImmutableList.of();
        // OR
        return Lists.newArrayList();
        // OR
        return new ArrayList<>();
    }
        
    final DescribeInstancesRequest request = new DescribeInstancesRequest()
            .withInstanceIds(ids);

    return ec2.describeInstances(request).getReservations();
}
```

**Example 问题示例：未设置 MaxResults**  
以下代码虽然检查并使用了 `nextToken`，但并未设置 `MaxResults`。  

```
private List<Reservation> describeMyInstances(final Collection<Filter> filters){
    final DescribeInstancesRequest request = new DescribeInstancesRequest()
            .withFilters(filters);

    List<Reservation> reservations = new ArrayList<>();
    String nextToken = null;
    do {
        request.setNextToken(nextToken);
        final DescribeInstancesResult response = ec2.describeInstances(request);
        reservations.addAll(response.getReservations());
        nextToken = response.getNextToken();
    } while (nextToken != null);

    return reservations;
}
```
要解决此问题，请按以下方式添加 `withMaxResults`。  

```
private List<Reservation> describeMyInstances(final Collection<Filter> filters){
    final DescribeInstancesRequest request = new DescribeInstancesRequest()
            .withFilters(filters)
            .withMaxResults(1000);

    List<Reservation> reservations = new ArrayList<>();
    String nextToken = null;
    do {
        request.setNextToken(nextToken);
        final DescribeInstancesResult response = ec2.describeInstances(request);
        reservations.addAll(response.getReservations());
        nextToken = response.getNextToken();
    } while (nextToken != null);

    return reservations;
}
```