配置客户端重试

Java 版 Cloud 客户端库使用重试来处理意外的暂时性故障(即服务器暂时不可用)。多次尝试可能会导致服务器返回成功响应。

默认重试值由运营云服务的团队选择。这些重试值是按 RPC 配置的。服务可以选择仅针对部分 RPC 启用重试。服务的每个 RPC 可能会配置为不同的值。

重试参数

客户端库有两种类型的重试参数可供配置:

  1. 重试状态代码:要重试的状态代码集。
  2. 重试超时或尝试次数上限:可配置的 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 的边界(尝试)由以下设置控制:

总 RPC 边界(一种操作)由以下设置控制:

重试 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 客户端库:

  1. 使用自定义配置创建 RetrySettings 类:

    RetrySettings customRetrySettings =
      RetrySettings.newBuilder()
        // ... Retry Configurations
        .build();
    RetrySettings customRetrySettings2 =
      RetrySettings.newBuilder()
        // ... Retry Configurations
        .build();
    
  2. 为客户端创建 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));
    

    提供的代码段正在为 AssetServiceClientExportAssets RPC 设置自定义重试配置。它将 ExportAssets RPC 配置为使用 customRetrySettings 中配置的重试设置,并将可重试的代码设置为 DEADLINE_EXCEEDED

  3. 创建客户端的设置,如 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 配置为以过高的频率运行。默认重试值由运营该服务的团队选择。

考虑增加重试延迟时间(初始重试延迟时间和重试乘数),以便重试尝试间隔更长,频率更低。请注意,这可能会导致回复速度变慢。

您的使用情形可能需要更快的响应速度或更频繁的重试尝试,或者两者兼而有之。如果是这种情况,请尝试提高配额限制。