Java 版 Cloud 客户端库使用重试来处理意外的暂时性故障(即服务器暂时不可用)。多次尝试可能会使服务器返回成功响应。
默认重试值由运营云服务的团队选择。这些重试值是按 RPC 配置的。服务可以选择仅为部分 RPC 启用重试。服务的每个 RPC 的配置可能不同。
重试参数
客户端库有两种类型的重试参数可供配置:
- 重试状态代码: 要重试的状态代码集。
- 重试超时或尝试次数上限: 可配置的 RetrySettings ,用于定义上限。
默认 RPC 重试配置位置
默认重试配置在生成的 {Client}StubSettings 文件中定义。以 Java-Asset v3.64.0 中的 ExportAssets RPC 为例,默认重试配置在以下位置定义:
重试状态代码: 在
AssetServiceStubSettings.java文件中配置。示例:ImmutableMap.Builder<String, ImmutableSet<StatusCode.Code>> definitions = ImmutableMap.builder(); definitions.put("no_retry_0_codes", ImmutableSet.copyOf(Lists.<StatusCode.Code>newArrayList())); // ... More StatusCode configurations RETRYABLE_CODE_DEFINITIONS = definitions.build();重试参数: 在
AssetServiceStubSettings.java文件中配置。 示例:ImmutableMap.Builder<String, RetrySettings> definitions = ImmutableMap.builder(); RetrySettings settings = null; settings = RetrySettings.newBuilder() .setInitialRpcTimeoutDuration(Duration.ofMillis(60000L)) .setRpcTimeoutMultiplier(1.0) .setMaxRpcTimeoutDuration(Duration.ofMillis(60000L)) .setTotalTimeoutDuration(Duration.ofMillis(60000L)) .build(); definitions.put("no_retry_0_params", settings); // ... More RetrySettings configurations RETRY_PARAM_DEFINITIONS = definitions.build();
这两种配置都映射到 AssetServiceStubSettings.java 文件中的 RPC。示例:
builder
.exportAssetsSettings()
.setRetryableCodes(RETRYABLE_CODE_DEFINITIONS.get("no_retry_0_codes"))
.setRetrySettings(RETRY_PARAM_DEFINITIONS.get("no_retry_0_params"));
客户端库重试概念
启用重试后,RPC 可以多次尝试,以实现成功调用。成功调用是指服务器返回 OK 状态代码(来自 gRPC)或 2xx 状态代码(来自 HttpJson)的响应。
尝试与操作
以下 RetrySettings 配置会修改 RPC 的尝试和操作的重试设置:
settings =
RetrySettings.newBuilder()
.setInitialRetryDelayDuration(Duration.ofMillis(100L))
.setRetryDelayMultiplier(1.3)
.setMaxRetryDelayDuration(Duration.ofMillis(60000L))
.setInitialRpcTimeoutDuration(Duration.ofMillis(60000L))
.setRpcTimeoutMultiplier(1.0)
.setMaxRpcTimeoutDuration(Duration.ofMillis(60000L))
.setTotalTimeoutDuration(Duration.ofMillis(60000L))
.build();
RPC 尝试是指进行的单次尝试,而 RPC 操作是指进行的所有尝试的集合。单个 RPC 调用将在单个操作中进行一次或多次尝试。
单个 RPC 上限(一次尝试)由以下设置控制:
setInitialRetryDelayDuration: 首次尝试之前的延迟时间。setRetryDelayMultiplier: 每次尝试之间应用的延迟时间乘数。setMaxRetryDelayDuration: 尝试可能的最大延迟时间。setInitialRpcTimeoutDuration: 首次尝试的超时时间。setRpcTimeoutMultiplier: 每次尝试之间应用的超时时间乘数。setMaxRpcTimeoutDuration: 尝试可能的最大超时时间。
RPC 总上限(一次操作)由以下设置控制:
setTotalTimeoutDuration: 整个操作允许的总超时时间。setMaxAttempts: 允许的最大尝试次数。
何时重试 RPC
在以下两种情况同时发生时,系统会重试 RPC:
- 库收到非成功状态代码,并且该状态代码标记为可以重试。
- RPC 调用超出单个 RPC 上限,但仍在 RPC 总上限范围内。
如果只有一种情况为 true,或者两种情况都不为 true,则系统不会重试 RPC。
例如,如果总超时时间尚未超出,但最新尝试收到的状态代码无法重试。
此外,在配置 RPC 上限时,您可以配置每次尝试的上限以及 RPC 总上限。重试算法将确保单次尝试的上限在 RPC 总上限范围内。
指数退避算法
指数退避算法会重试请求,并且每次重试尝试之间的延迟时间会逐渐增加。此重试延迟时间值可以设置上限。
例如,以下重试配置可能会导致以下延迟时间:
Initial Retry Delay: 100ms
Retry Delay Multiplier: 2.0
Max Retry Delay: 500ms
- 尝试 1:延迟 100 毫秒
- 尝试 2:延迟 200 毫秒
- 尝试 3:延迟 400 毫秒
- 尝试 4:延迟 500 毫秒
- …
- 尝试 X:延迟 500 毫秒
抖动
抖动是指使用随机性添加方差,以分散 RPC 的 调用时间。 Google Cloud 客户端库始终为 重试启用抖动。这有助于分散重试尝试,而不会使服务器不堪重负。
抖动随机值是根据重试延迟时间计算得出的。在每次尝试之前,重试算法都会计算 [1, RETRY_DELAY] 之间的随机值。此计算值是请求发送到服务器之前的近似延迟时间。
以下重试配置利用了抖动和指数退避算法。
Initial Retry Delay: 100ms
Retry Delay Multiplier: 2.0
Max Retry Delay: 500ms
这可能会导致以下延迟时间:
- 尝试 1:延迟
[1, 100]毫秒之间的随机值 - 尝试 2:延迟
[1, 200]毫秒之间的随机值 - 尝试 3:延迟
[1, 400]毫秒之间的随机值 - 尝试 4:延迟
[1, 500]毫秒之间的随机值 - …
- 尝试 X:延迟
[1, 500]毫秒之间的随机值
重试示例
以下示例展示了一些重试配置的行为。
不重试
此示例会停用重试。
RetrySettings defaultNoRetrySettings =
RetrySettings.newBuilder()
// Use the default configurations for other settings
.setTotalTimeoutDuration(Duration.ofMillis(5000L))
// Explicitly set retries as disabled (maxAttempts == 1)
.setMaxAttempts(1)
.build();
或者,您可以使用以下示例配置此行为:
RetrySettings defaultNoRetrySettings =
RetrySettings.newBuilder()
.setLogicalTimeoutDuration(Duration.ofMillis(5000L))
.build();
下表显示了尝试次数:
| 尝试次数 | RPC 超时时间 | 重试延迟时间 | 调用时间 | 调用结束时间 |
|---|---|---|---|---|
| 1 | 5000 毫秒 | 0 毫秒 | 0 毫秒 | 5000 毫秒 |
重试示例
此示例启用重试,并指定延迟时间和超时时间。
RetrySettings.newBuilder()
.setInitialRetryDelayDuration(Duration.ofMillis(200L))
.setRetryDelayMultiplier(2.0)
.setMaxRetryDelayDuration(Duration.ofMillis(500L))
.setInitialRpcTimeoutDuration(Duration.ofMillis(1500L))
.setRpcTimeoutMultiplier(2.0)
.setMaxRpcTimeoutDuration(Duration.ofMillis(3000L))
.setTotalTimeoutDuration(Duration.ofMillis(5000L))
.build();
下表显示了尝试次数:
| 尝试次数 | RPC 超时时间 | 重试延迟时间 | 调用时间 | 调用结束时间 |
|---|---|---|---|---|
| 1 | 1500 毫秒 | 0 毫秒 | 0 毫秒 | 1500 毫秒 |
| 2(重试) | 3000 毫秒 | 200 毫秒 | 1700 毫秒 | 4700 毫秒 |
| 3(未尝试重试) | - | 400 毫秒 | - | - |
重试示例:更长的总超时时间
此示例与第一个重试示例类似,但总超时时间更长,以展示额外的重试尝试和最后一次重试尝试的 RPC 超时时间上限。
RetrySettings.newBuilder()
.setInitialRetryDelayDuration(Duration.ofMillis(200L))
.setRetryDelayMultiplier(2.0)
.setMaxRetryDelayDuration(Duration.ofMillis(500L))
.setInitialRpcTimeoutDuration(Duration.ofMillis(1500L))
.setRpcTimeoutMultiplier(2.0)
.setMaxRpcTimeoutDuration(Duration.ofMillis(3000L))
.setTotalTimeoutDuration(Duration.ofMillis(10000L))
.build();
下表显示了尝试次数:
| 尝试次数 | RPC 超时时间 | 重试延迟时间 | 调用时间 | 调用结束时间 |
|---|---|---|---|---|
| 1 | 1500 毫秒 | 0 毫秒 | 0 毫秒 | 1500 毫秒 |
| 2(重试) | 3000 毫秒 | 200 毫秒 | 1700 毫秒 | 4700 毫秒 |
| 3(重试) | 4900 毫秒 | 400 毫秒 | 5100 毫秒 | 10000 毫秒 |
第三次重试 RPC 超时时间值受总超时时间值的限制。 将乘数 (2.0) 与之前的超时时间值 (3000ms) 相乘,得出 RPC 超时时间为 6000 毫秒。不过,RPC 超时时间不应超过总超时时间,因此会减少到“剩余时间”(10000 - 5100 = 4900)。
重试示例:RPC 超时时间上限
RetrySettings defaultRetrySettings =
RetrySettings.newBuilder()
.setInitialRetryDelayDuration(Duration.ofMillis(200L))
.setRetryDelayMultiplier(2.0)
.setMaxRetryDelayDuration(Duration.ofMillis(500L))
.setInitialRpcTimeoutDuration(Duration.ofMillis(500L))
.setRpcTimeoutMultiplier(2.0)
.setMaxRpcTimeoutDuration(Duration.ofMillis(2000L))
.setTotalTimeoutDuration(Duration.ofMillis(4000L))
.build();
下表显示了尝试次数:
| 尝试次数 | RPC 超时时间 | 重试延迟时间 | 调用时间 | 调用结束时间 |
|---|---|---|---|---|
| 1 | 500 毫秒 | 0 毫秒 | 0 毫秒 | 500 毫秒 |
| 2(重试) | 1000 毫秒 | 200 毫秒 | 700 毫秒 | 1700 毫秒 |
| 3(重试) | 1900 毫秒 | 400 毫秒 | 2100 毫秒 | 4000 毫秒 |
另一个示例,其中 RPC 超时时间上限不超过总超时时间。
如何为 RPC 配置自定义重试参数
以下示例使用 Java-Asset 客户端库:
使用自定义配置创建
RetrySettings类:RetrySettings customRetrySettings = RetrySettings.newBuilder() // ... Retry Configurations .build(); RetrySettings customRetrySettings2 = RetrySettings.newBuilder() // ... Retry Configurations .build();为客户端创建
StubSettings.Builder,并为 RPC 配置它:AssetServiceStubSettings.Builder assetStubSettingsBuilder = AssetServiceStubSettings.newBuilder(); assetStubSettingsBuilder .exportAssetsSettings() // Set your custom Retry Settings .setRetrySettings(customRetrySettings) // Set your custom Retryable Codes .setRetryableCodes(ImmutableSet.of(StatusCode.Code.DEADLINE_EXCEEDED));提供的代码段为
AssetServiceClient的ExportAssetsRPC 设置自定义重试配置。它将ExportAssetsRPC 配置为使用customRetrySettings中配置的重试设置,并将可以重试的代码设置为DEADLINE_EXCEEDED。为客户端创建设置,如
assetSettings:AssetServiceSettings assetSettings = AssetServiceSettings.create(assetStubSettingsBuilder.build());使用设置创建客户端,如
assetClient。try (AssetServiceClient assetClient = AssetServiceClient.create(assetSettings)) { ... }
针对要配置的每个 RPC 重复第 2 步。例如:
AssetServiceStubSettings.Builder assetStubSettingsBuilder = AssetServiceStubSettings.newBuilder();
// Modify the retry params for ExportAssets RPC
assetStubSettingsBuilder
.exportAssetsSettings()
.setRetrySettings(customRetrySettings)
.setRetryableCodes(ImmutableSet.of(StatusCode.Code.DEADLINE_EXCEEDED));
// Modify the retry params for ListAssets RPC
assetStubSettingsBuilder
.listAssetsSettings()
.setRetrySettings(customRetrySettings2)
.setRetryableCodes(ImmutableSet.of(StatusCode.Code.UNAVAILABLE));
常见问题解答
以下是有关客户端重试行为的常见问题。
我预计会进行 X 次重试尝试,但实际尝试了 Y 次。
除非您明确指定最大尝试次数(同时停用超时配置),否则您可能无法始终看到相同的重试尝试次数。RPC 延迟时间的抖动随机值使得难以预测请求的实际发送时间。
RPC 在达到总超时时间值之前返回了失败。
重试算法会在每次重试尝试期间计算抖动重试延迟时间值。计算出的重试延迟时间将安排在未来运行(即 currentTime() + jitteredRetryDelay)。如果安排的尝试时间超过总超时时间,则不会进行最终的重试尝试。
我配置了自定义设置,但遇到了配额问题。
您可能已将 RetrySettings 配置为过于激进地运行。默认重试值由运营服务的团队选择。
请考虑增加重试延迟时间(初始重试延迟时间和重试乘数),以便重试尝试间隔更长,频率更低。请注意,这可能会导致响应速度变慢。
您的使用场景可能需要更快的响应速度或更频繁的重试尝试,或者两者兼而有之。如果是这种情况,请尝试提高配额限制。