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 边界(一种操作)由以下设置控制:
setTotalTimeout:整个操作允许的总超时时间。setMaxAttempts:允许的最大尝试次数。
重试 RPC 时
当同时出现以下两种情况时,系统会重试 RPC:
- 库收到非成功状态代码,并且该状态代码被标记为可以重试。
- RPC 调用超出单个 RPC 边界,但仍在总 RPC 边界内。
如果只有一个场景为 true,或者两个场景均为 false,则不会重试 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) 与之前的超时值 (3000 毫秒) 相乘,可得到 6000 毫秒的 RPC 超时。不过,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所示:java AssetServiceSettings assetSettings = AssetServiceSettings.create(assetStubSettingsBuilder.build());4.使用assetClient所示的设置创建客户端。java 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 配置为以过高的频率运行。默认重试值由运营该服务的团队选择。
考虑增加重试延迟时间(初始重试延迟时间和重试乘数),以便重试尝试间隔更长,频率更低。请注意,这可能会导致回复速度变慢。
您的使用情形可能需要更快的响应速度或更频繁的重试尝试,或者两者兼而有之。如果是这种情况,请尝试提高配额限制。