本页面介绍了 Cloud Storage 工具如何重试失败的请求以及如何自定义重试的行为,本文档还介绍了重试请求的注意事项。
概览
有两个因素决定了能否安全地重试请求:
- 您从请求中收到的响应。
- 请求的幂等性。
响应
您从请求收到的响应表明重试请求是否有用。与暂时性问题相关的响应通常可以重试。另一方面,与永久错误相关的响应表明您需要进行更改(例如更改授权或配置),然后重试请求才有用。以下响应表明可用于重试的暂时性问题:
- HTTP
408
、429
和5xx
响应代码。 - 套接字超时和 TCP 断开连接。
如需了解详情,请参阅 JSON 和 XML 的状态和错误代码。
幂等性
幂等请求意味着请求可以重复执行,并且始终使目标资源处于相同的结束状态。例如,列出请求始终具有幂等性,因为此类请求不会修改资源。另一方面,创建新的 Pub/Sub 通知从不具有幂等性,因为它在每次请求成功时创建新的通知 ID。
以下是使操作具有幂等性的条件示例:
即使持续请求目标资源,操作也会对目标资源产生相同的可观察到的影响。
操作仅成功一次。
操作不会对目标资源的状态产生任何可观察到的影响。
收到可重试响应时,您应该考虑请求的幂等性,因为重试非幂等请求可能会导致竞态条件和其他冲突。
条件式幂等性
一部分请求具有条件式幂等性,这意味着这些请求仅在包含特定可选参数时才具有幂等性。默认情况下,只有在条件情况通过时,才应对重试有条件安全的操作进行重试。Cloud Storage 接受前提条件和 ETag 作为请求的条件情况。
操作的幂等性
下表列出了属于每种幂等性的 Cloud Storage 操作。
幂等性 | 运维 |
---|---|
始终具有幂等性 |
|
有条件地具有幂等性 |
|
永不幂等 |
|
1此字段可在 JSON API 中使用。如需了解可在客户端库中使用的字段,请参阅相关的客户端库文档。
Cloud Storage 工具如何实现重试策略
控制台
Google Cloud 控制台会代表您向 Cloud Storage 发送请求,并处理任何必要的退避操作。
命令行
gcloud storage
命令会重试响应部分中列出的错误,您无需执行其他操作。您可能需要针对其他错误执行操作,例如:
凭据无效或权限不足。
由于代理配置问题,网络不可达。
对于可重试的错误,gcloud CLI 会使用截断的二进制指数退避算法策略重试请求。gcloud CLI 的默认重试次数上限为 32。
客户端库
C++
默认情况下,操作支持针对以下 HTTP 错误代码进行重试,以及针对指示连接丢失或从未成功建立的任何套接字错误进行重试。
408 Request Timeout
429 Too Many Requests
500 Internal Server Error
502 Bad Gateway
503 Service Unavailable
504 Gateway Timeout
C++ 库中的所有指数退避算法和重试设置均可配置。如果库中实施的算法不支持您的需求,您可以提供自定义代码来实现自己的策略。
设置 | 默认值 |
---|---|
自动重试 | True |
重试请求的最长时间 | 15 分钟 |
初始等待时间(退避时间) | 1 秒 |
每次迭代的等待时间乘数 | 2 |
最长等待时间 | 5 分钟 |
默认情况下,C++ 库会重试所有具有可重试错误的操作(即使是从不具有幂等性的操作),并且可以在重复尝试成功后删除或创建多个资源。如需仅重试具有幂等性的操作,请使用 google::cloud::storage::StrictIdempotencyPolicy
类。
C#
C# 客户端库默认使用指数退避算法。
Go
默认情况下,操作支持重试以下错误:
- 连接错误:
io.ErrUnexpectedEOF
:这可能是由于暂时性的网络问题导致的。- 包含
connection refused
的url.Error
:这可能是由于暂时性的网络问题导致的。 - 包含
connection reset by peer
的url.Error
:这意味着 Google Cloud 已重置连接。 net.ErrClosed
:这意味着 Google Cloud 已关闭连接。
- HTTP 代码:
408 Request Timeout
429 Too Many Requests
500 Internal Server Error
502 Bad Gateway
503 Service Unavailable
504 Gateway Timeout
- 实现
Temporary()
接口并赋予值err.Temporary() == true
的错误 - 使用 Go 1.13 错误封装封装的上述任何错误
Go 库中的所有指数退避算法设置都是可配置的。默认情况下,Go 中的操作使用以下指数退避算法设置(默认值取自 gax):
设置 | 默认值(以秒为单位) |
---|---|
自动重试 | 如果是幂等的,则为 true |
尝试次数上限 | 无限制 |
初次重试延迟 | 1 秒 |
重试延迟乘数 | 2.0 |
重试延迟上限 | 30 秒 |
总超时(可续传上传数据块) | 32 秒 |
总超时(所有其他操作) | 无限制 |
一般而言,除非控制上下文被取消、客户端关闭或收到非暂时性错误,否则重试将无限期地继续。如需阻止重试继续,请使用上下文超时或取消。此行为的唯一例外情况是使用 Writer 执行可续传上传时,其中数据足够大,需要多个请求。在这种情况下,每个数据块默认超时并在 32 秒后停止重试。您可以通过更改 Writer.ChunkRetryDeadline
来调整默认超时。
一部分 Go 操作属于有条件地幂等(有条件地安全重试)。这些操作仅在满足特定条件时才会重试:
GenerationMatch
或Generation
- 如果对调用应用了
GenerationMatch
前提条件或设置了ObjectHandle.Generation
,则重试安全。
- 如果对调用应用了
MetagenerationMatch
- 如果对调用应用了
MetagenerationMatch
前提条件,则重试安全。
- 如果对调用应用了
Etag
- 如果方法将
etag
插入到 JSON 请求正文,则重试安全。仅在设置了HmacKeyMetadata.Etag
时才会在HMACKeyHandle.Update
中使用。
- 如果方法将
RetryPolicy
默认设置为 RetryPolicy.RetryIdempotent
。如需查看有关如何修改默认重试行为的示例,请参阅自定义重试。
Java
默认情况下,操作支持重试以下错误:
- 连接错误:
Connection reset by peer
:这意味着 Google Cloud 已重置连接。Unexpected connection closure
:这意味着 Google Cloud 已关闭连接。
- HTTP 代码:
408 Request Timeout
429 Too Many Requests
500 Internal Server Error
502 Bad Gateway
503 Service Unavailable
504 Gateway Timeout
Java 库中的所有指数退避算法设置都是可配置的。默认情况下,通过 Java 执行的操作会使用以下指数退避算法设置:
设置 | 默认值(以秒为单位) |
---|---|
自动重试 | 如果是幂等的,则为 true |
尝试次数上限 | 6 |
初次重试延迟 | 1 秒 |
重试延迟乘数 | 2.0 |
重试延迟上限 | 32 秒 |
总超时 | 50 秒 |
初始远程过程调用 (RPC) 超时 | 50 秒 |
远程过程调用 (RPC) 超时乘数 | 1.0 |
远程过程调用 (RPC) 超时上限 | 50 秒 |
连接超时 | 20 秒 |
读取超时 | 20 秒 |
如需详细了解这些设置,请参阅 RetrySettings.Builder
和 HttpTransportOptions.Builder
的 Java 参考文档。
一部分 Java 操作属于有条件地幂等(有条件地安全重试)。这些操作只能在包含特定参数时重试:
ifGenerationMatch
或generation
- 如果已将
ifGenerationMatch
或generation
作为选项传入方法,则重试安全。
- 如果已将
ifMetagenerationMatch
- 如果作为选项传入
ifMetagenerationMatch
,则重试安全。
- 如果作为选项传入
StorageOptions.setStorageRetryStrategy
默认设置为 StorageRetryStrategy#getDefaultStorageRetryStrategy
。
如需查看有关如何修改默认重试行为的示例,请参阅自定义重试。
Node.js
默认情况下,操作支持重试以下错误代码:
- 连接错误:
EAI_again
:这是 DNS 查找错误。如需了解详情,请参阅getaddrinfo
文档。Connection reset by peer
:这意味着 Google Cloud 已重置连接。Unexpected connection closure
:这意味着 Google Cloud 已关闭连接。
- HTTP 代码:
408 Request Timeout
429 Too Many Requests
500 Internal Server Error
502 Bad Gateway
503 Service Unavailable
504 Gateway Timeout
Node.js 库中的所有指数退避算法设置都是可配置的。 默认情况下,通过 Node.js 执行的操作使用以下指数退避算法设置:
设置 | 默认值(以秒为单位) |
---|---|
自动重试 | 如果是幂等的,则为 true |
重试次数上限 | 3 |
初始等待时间 | 1 秒 |
每次迭代的等待时间乘数 | 2 |
最长等待时间 | 64 秒 |
默认截止时间 | 600 秒 |
一部分 Node.js 操作属于有条件地幂等(有条件地安全重试)。这些操作只能在包含特定参数时重试:
ifGenerationMatch
或generation
- 如果已将
ifGenerationMatch
或generation
作为选项传入方法,则重试安全。通常,方法只会接受这两个参数中的一个。
- 如果已将
ifMetagenerationMatch
- 如果作为选项传入
ifMetagenerationMatch
,则重试安全。
- 如果作为选项传入
retryOptions.idempotencyStrategy
默认设置为 IdempotencyStrategy.RetryConditional
。如需查看有关如何修改默认重试行为的示例,请参阅自定义重试。
PHP
PHP 客户端库默认使用指数退避算法。
Python
默认情况下,操作支持重试以下错误代码:
- 连接错误:
requests.exceptions.ConnectionError
requests.exceptions.ChunkedEncodingError
(仅适用于将载荷数据提取或发送到对象的操作,例如上传和下载)ConnectionError
- HTTP 代码:
408 Request Timeout
429 Too Many Requests
500 Internal Server Error
502 Bad Gateway
503 Service Unavailable
504 Gateway Timeout
通过 Python 执行的操作使用以下指数退避算法默认设置:
设置 | 默认值(以秒为单位) |
---|---|
自动重试 | 如果是幂等的,则为 true |
初始等待时间 | 1 |
每次迭代的等待时间乘数 | 2 |
最长等待时间 | 60 |
默认截止时间 | 120 |
有一部分 Python 操作在包含特定参数时具有条件幂等性(有条件地安全重试)。只有满足条件时,这些操作才会重试:
DEFAULT_RETRY_IF_GENERATION_SPECIFIED
- 如果已将
generation
或if_generation_match
作为参数传入方法,则重试安全。通常,方法只会接受这两个参数中的一个。
- 如果已将
DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED
- 如果已将
if_metageneration_match
作为参数传入方法,则重试安全。
- 如果已将
DEFAULT_RETRY_IF_ETAG_IN_JSON
- 如果方法将
etag
插入到 JSON 请求正文,则重试安全。对于HMACKeyMetadata.update()
,这意味着必须对HMACKeyMetadata
对象本身设置 etag。对于其他类的set_iam_policy()
方法,这意味着必须在传入方法的“policy”参数中设置 etag。
- 如果方法将
Ruby
默认情况下,操作支持重试以下错误代码:
- 连接错误:
SocketError
HTTPClient::TimeoutError
Errno::ECONNREFUSED
HTTPClient::KeepAliveDisconnected
- HTTP 代码:
408 Request Timeout
429 Too Many Requests
5xx Server Error
Ruby 客户端库中的所有指数退避算法设置都是可配置的。默认情况下,通过 Ruby 客户端库执行的操作使用以下指数退避算法设置:
设置 | 默认值 |
---|---|
自动重试 | True |
重试次数上限 | 3 |
初始等待时间 | 1 秒 |
每次迭代的等待时间乘数 | 2 |
最长等待时间 | 60 秒 |
默认截止时间 | 900 秒 |
有一部分 Ruby 操作在包含特定参数时具有条件幂等性(有条件地安全重试):
if_generation_match
或generation
- 如果将
generation
或if_generation_match
参数作为参数传递给方法,则重试安全。通常,方法只会接受这两个参数中的一个。
- 如果将
if_metageneration_match
- 如果将
if_metageneration_match
参数作为选项传入,则重试安全。
- 如果将
默认情况下,系统会重试所有幂等操作,并且仅在条件 case 通过时才会重试有条件的幂等操作。系统不会重试非幂等操作。如需查看有关如何修改默认重试行为的示例,请参阅自定义重试。
REST API
直接调用 JSON 或 XML API 时,您应该使用指数退避算法来实现您自己的重试策略。
自定义重试
控制台
您无法使用 Google Cloud 控制台自定义重试行为。
命令行
对于 gcloud storage
命令,您可以通过创建命名配置并设置以下部分或全部属性来控制重试策略:
base_retry_delay
exponential_sleep_multiplier
max_retries
max_retry_delay
然后,您可以使用 --configuration
项目范围标志来按命令应用定义的配置,也可以使用 gcloud config set
命令为所有 gcloud 命令应用定义的配置。
客户端库
C++
如需自定义重试行为,请在初始化 google::cloud::storage::Client
对象时为以下选项提供值:
google::cloud::storage::RetryPolicyOption
:该库提供google::cloud::storage::LimitedErrorCountRetryPolicy
和google::cloud::storage::LimitedTimeRetryPolicy
类。您可以提供自己的类,该类必须实现google::cloud::RetryPolicy
接口。google::cloud::storage::BackoffPolicyOption
:该库提供google::cloud::storage::ExponentialBackoffPolicy
类。您可以提供自己的类,该类必须实现google::cloud::storage::BackoffPolicy
接口。google::cloud::storage::IdempotencyPolicyOption
:库提供google::cloud::storage::StrictIdempotencyPolicy
和google::cloud::storage::AlwaysRetryIdempotencyPolicy
类。您可以提供自己的类,该类必须实现google::cloud::storage::IdempotencyPolicy
接口。
如需了解详情,请参阅 C++ 客户端库参考文档。
C#
您无法自定义 C# 客户端库使用的默认重试策略。
Go
当您初始化存储客户端时,系统将设置默认的重试配置。除非被替换,否则配置中的选项会设置为默认值。用户可以为客户端发出的单个库调用(使用 BucketHandle.Retryer 和 ObjectHandle.Retryer)或所有调用(使用 Client.SetRetry)配置非默认重试行为。如需修改重试行为,请将相关的 RetryOptions 传递给以下方法之一。
如需了解如何自定义重试行为,请参阅以下代码示例。
Java
初始化 Storage
时,也会初始化 RetrySettings
的实例。除非被替换,否则 RetrySettings
中的选项会设置为默认值。如需修改默认的自动重试行为,请将自定义 StorageRetryStrategy
传入用于构建 Storage
实例的 StorageOptions
。如需修改任何其他标量参数,请将自定义 RetrySettings
传入用于构建 Storage
实例的 StorageOptions
。
如需了解如何自定义重试行为,请参阅以下示例:
Node.js
初始化 Cloud Storage 时,系统还会初始化 retryOptions 配置文件。除非被替换,否则配置中的选项会设置为默认值。要修改默认重试行为,请在初始化时将自定义重试配置 retryOptions
传递到存储构造函数中。Node.js 客户端库可以自动使用退避策略来重试带有 autoRetry
参数的请求。
如需了解如何自定义重试行为,请参阅以下代码示例。
PHP
您无法自定义 PHP 客户端库使用的默认重试策略。
Python
如需修改默认重试行为,请使用 with_XXX
方法调用 google.cloud.storage.retry.DEFAULT_RETRY
对象来创建该对象的副本。如果添加 DEFAULT_RETRY
参数,Python 客户端库会自动使用退避时间策略重试请求。
请注意,对于将载荷数据提取或发送到对象的操作(例如上传和下载),系统不支持 with_predicate
。建议您逐个修改特性。如需了解详情,请参阅 google-api-core 重试参考文档。
如需配置您自己的条件性重试,请创建 ConditionalRetryPolicy
对象,并使用 DEFAULT_RETRY_IF_GENERATION_SPECIFIED
、DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED
或 DEFAULT_RETRY_IF_ETAG_IN_JSON
封装自定义 Retry
对象。
如需了解如何自定义重试行为,请参阅以下代码示例。
Ruby
初始化存储客户端时,所有重试配置都会设置为上表中显示的值。如需修改默认重试行为,请在初始化存储客户端时传递重试配置。
如需替换特定操作的重试次数,请将 retries
传入操作的 options
参数。
REST API
使用指数退避算法实现您自己的重试策略。
指数退避算法
指数退避算法以指数方式重试请求(不断增加各次请求之间的等待时间,直到达到最大退避时间)。您通常应该将指数退避算法与抖动结合使用,以重试同时满足响应和幂等性条件的请求。如需了解使用指数退避算法实现自动重试的最佳做法,请参阅解决级联故障。
后续步骤
- 详细了解请求前提条件。