設定用戶端重試

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 毫秒 4700ms
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 毫秒 4700ms
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 (Retry) 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. 建立用戶端設定,如 assetSettingsjava AssetServiceSettings assetSettings = AssetServiceSettings.create(assetStubSettingsBuilder.build()); 4. 使用設定建立用戶端,如 assetClientjava 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 設為過於積極地執行。服務營運團隊會選擇預設的重試值。

請考慮增加重試延遲時間 (初始重試延遲時間和重試乘數),讓重試作業間隔更長,頻率更低。請注意,這可能會導致回覆速度較慢。

您的用途可能需要更快速的回應或更頻繁的重試次數,或兩者皆是。如果是這樣,請嘗試提高配額限制。