重試策略

5 min read Original article ↗

本頁說明 Cloud Storage 工具如何重試失敗的要求,以及如何自訂重試行為。此外,本文也會說明重試要求時的注意事項。

總覽

有兩個因素會決定要求是否可安全重試:

  • 您從要求收到的回應

  • 要求的冪等性

回應

您從要求收到的回應會指出是否值得重試要求。與暫時性問題相關的回應通常可以重試。另一方面,如果回應與永久性錯誤相關,表示您需要進行變更 (例如授權或設定變更),才能再次嘗試提出要求。下列回應表示暫時性問題,建議重試:

  • HTTP 4084295xx 回應代碼。
  • 通訊端逾時和 TCP 中斷連線。

詳情請參閱 JSONXML 的狀態和錯誤代碼。

冪等

冪等要求可重複執行,不會改變目標資源的最終狀態,每次都會產生相同的最終狀態。舉例來說,列出作業一律為等冪,因為這類要求不會修改資源。另一方面,建立新的 Pub/Sub 通知絕不會是等冪作業,因為每次要求成功時,系統都會建立新的通知 ID。

以下是讓作業具備等冪性的條件範例:

  • 即使持續要求,這項作業對目標資源產生的可觀察效果仍相同。

  • 這項作業只會成功一次。

  • 這項作業對目標資源的狀態沒有可觀察到的影響。

收到可重試的回應時,請考慮要求的等冪性,因為重試非等冪要求可能會導致競爭條件和其他衝突。

條件式冪等性

部分要求是有條件的等冪,也就是說,只有在包含特定選用引數時,要求才會是等冪。如果作業在特定條件下可安全重試,則只有在條件案例通過時,系統才會根據預設重試作業。Cloud Storage 接受先決條件和 ETag 做為要求的條件案例。

作業的冪等性

下表列出各類冪等性的 Cloud Storage 作業。

冪等 作業
一律為等冪
  • 所有 get 和 list 要求
  • 插入或刪除值區
  • 測試 bucket 身分與存取權管理政策和權限
  • 鎖定保留政策
  • 刪除 HMAC 金鑰或 Pub/Sub 通知
有條件等冪
  • IfMetagenerationMatch1etag1 做為 HTTP 先決條件,更新/修補 Bucket 的要求
  • IfMetagenerationMatch1etag1 做為 HTTP 先決條件,更新/修補物件的要求
  • 使用 etag1 做為 HTTP 前置條件或資源主體,設定 bucket IAM 政策
  • 使用 etag1 做為 HTTP 前置條件或資源主體,更新 HMAC 金鑰
  • 使用 ifGenerationMatch1 插入、複製、編寫或重寫物件
  • 使用 ifGenerationMatch1 刪除物件 (或使用物件版本的產生編號)
永不具備等冪性
  • 建立 HMAC 金鑰
  • 建立 Pub/Sub 通知
  • 建立、刪除或傳送值區和物件 ACL 或預設物件 ACL 的 patch/update 要求

1這個欄位可用於 JSON API。如要瞭解用戶端程式庫可使用的欄位,請參閱相關的用戶端程式庫說明文件

控制台

Google Cloud 控制台會代表您向 Cloud Storage 傳送要求,並處理所有必要的輪詢。

指令列

gcloud storage 指令會重試「回應」一節中列出的錯誤,您不必採取額外行動。您可能需要針對其他錯誤採取行動,例如:

  • 憑證無效或權限不足。

  • Proxy 設定有問題,因此無法連上網路。

如果發生可重試的錯誤,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++ 程式庫中的所有指數輪詢和重試設定都可以設定。如果程式庫中實作的演算法無法滿足您的需求,您可以提供自訂程式碼來實作自己的策略。

設定 預設值
自動重試
要求重試次數上限 15 分鐘
初始等待 (輪詢) 時間 1 秒
每次疊代的等待時間乘數 2
等待時間上限 5 分鐘

根據預設,C++ 程式庫會重試所有作業,即使這些作業永遠不會是等冪作業,且重複成功時可能會刪除或建立多個資源,也會重試。如要僅重試等冪作業,請使用 google::cloud::storage::StrictIdempotencyPolicy 類別。

C#

C# 用戶端程式庫預設使用指數輪詢

Go

根據預設,作業支援下列錯誤的重試作業:

  • 連線錯誤:
    • io.ErrUnexpectedEOF:這可能是暫時性的網路問題所致。
    • url.Error 含有 connection refused:這可能是暫時性的網路問題所致。
    • 包含 connection reset by peerurl.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 作業是條件式等冪 (條件式安全重試)。只有在符合特定條件時,這些作業才會重試:

  • GenerationMatchGeneration

    • 如果對呼叫套用了 GenerationMatch 前置條件,或已設定 ObjectHandle.Generation,則可安全地重試。
  • MetagenerationMatch

    • 如果呼叫套用了 MetagenerationMatch 前置條件,即可安全地重試。
  • Etag

    • 如果方法會在 JSON 要求主體中插入 etag,則可以安全地重試。僅在 HMACKeyHandle.Update 中使用,且必須已設定 HmacKeyMetadata.Etag

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.BuilderHttpTransportOptions.Builder 的 Java 參考說明文件。

有一部分 Java 作業是條件式等冪 (條件式安全重試)。只有在包含特定引數時,這些作業才會重試:

  • ifGenerationMatchgeneration

    • 如果 ifGenerationMatchgeneration 已做為方法選項傳遞,可以安全地重試。
  • 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 作業是條件式等冪 (條件式安全重試)。只有在這些作業包含特定引數時,才會重試:

  • ifGenerationMatchgeneration

    • 如果 ifGenerationMatchgeneration 已做為方法選項傳遞,可以安全地重試。方法通常只接受這兩個參數的其中一個。
  • ifMetagenerationMatch

    • 如果 ifMetagenerationMatch 是以選項形式傳入,則可安全地重試。

retryOptions.idempotencyStrategy 預設為 IdempotencyStrategy.RetryConditional。如要瞭解如何修改預設重試行為,請參閱「自訂重試」一文中的範例。

PHP

PHP 用戶端程式庫預設使用指數輪詢

根據預設,作業支援下列錯誤代碼的重試作業:

  • 連線錯誤:
    • connetion-refused:這可能是暫時性的網路問題所致。
    • connection-reset:這表示 Google Cloud 已重設連線。
  • HTTP 程式碼:
    • 200:適用於部分下載案例
    • 408 Request Timeout
    • 429 Too Many Requests
    • 500 Internal Server Error
    • 502 Bad Gateway
    • 503 Service Unavailable
    • 504 Gateway Timeout

PHP 程式庫中的部分指數輪詢設定可供設定。根據預設,透過 PHP 執行的作業會使用下列指數輪詢設定:

設定 預設值 (以秒為單位)
自動重試 如果是冪等,則為 True
初始重試延遲時間 1 秒
重試延遲時間乘數 2.0
重試延遲時間上限 60 秒
要求逾時 REST 為 0,gRPC 為 60
預設重試次數 3

有一部分 PHP 作業是條件式等冪 (條件式安全重試)。只有在這些作業包含特定引數時,才會重試:

  • ifGenerationMatchgeneration

    • 如果 ifGenerationMatchgeneration 已做為方法選項傳遞,可以安全地重試。方法通常只接受這兩個參數的其中一個。
  • ifMetagenerationMatch

    • 如果 ifMetagenerationMatch 是以選項形式傳入,則可安全地重試。

建立 StorageClient 時,系統預設會使用 StorageClient::RETRY_IDEMPOTENT 策略。如要瞭解如何修改預設重試行為,請參閱自訂重試一節的範例。

Python

根據預設,作業支援下列錯誤代碼的重試作業:

  • 連線錯誤:
    • requests.exceptions.ConnectionError
    • requests.exceptions.ChunkedEncodingError (僅適用於擷取或傳送酬載資料至物件的作業,例如上傳和下載)
    • ConnectionError
    • http.client.ResponseNotReady
    • urllib3.exceptions.TimeoutError
  • 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

除了一律為等冪的 Cloud Storage 作業外,Python 用戶端程式庫預設會自動重試 Objects: insertObjects: deleteObjects: patch

如果包含特定引數,部分 Python 作業會成為有條件的等冪作業 (可安全地重試)。只有在通過條件案例時,這些作業才會重試:

  • DEFAULT_RETRY_IF_GENERATION_SPECIFIED

    • 如果 generationif_generation_match 已做為引數傳遞至方法,則可安全地重試。方法通常只接受這兩個參數的其中一個。
  • DEFAULT_RETRY_IF_METAGENERATION_SPECIFIED

    • 如果 if_metageneration_match 是以引數形式傳遞至方法,可以安全地重試。
  • DEFAULT_RETRY_IF_ETAG_IN_JSON

    • 如果方法會在 JSON 要求主體中插入 etag,則可以安全地重試。如果是 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 用戶端程式庫預設會使用下列設定,透過指數輪詢執行作業:

設定 預設值
自動重試
重試次數上限 3
初始等待時間 1 秒
每次疊代的等待時間乘數 2
等待時間上限 60 秒
預設截止日期 900 秒

如果包含特定引數,則有部分 Ruby 作業會成為有條件的等冪作業 (可安全地重試):

  • if_generation_matchgeneration

    • 如果 generationif_generation_match 參數做為引數傳遞至方法,可以安全地重試。方法通常只接受這兩個參數之一。
  • if_metageneration_match

    • 如果 if_metageneration_match 參數以選項形式傳入,可以安全地重試。

根據預設,系統會重試所有等冪作業,且只有在條件案例通過時,才會重試有條件的等冪作業。系統不會重試非等冪運算。如要瞭解如何修改預設重試行為,請參閱「自訂重試」一節的範例。

REST API

直接呼叫 JSON 或 XML API 時,您應使用指數輪詢演算法,自行導入重試策略。

自訂重試次數

控制台

您無法使用 Google Cloud 控制台自訂重試行為。

指令列

如果是 gcloud storage 指令,您可以建立具名設定,並設定下列部分或所有屬性,藉此控管重試策略:

設定 預設值 (以秒為單位)
base_retry_delay 1
exponential_sleep_multiplier 2
max_retries 32
max_retry_delay 32

接著,您可以透過--configuration專案範圍標記,為每個指令套用定義的設定,也可以使用 gcloud config set 指令,為所有 Google Cloud CLI 指令套用設定。

用戶端程式庫

C++

如要自訂重試行為,請在初始化 google::cloud::storage::Client 物件時,為下列選項提供值:

  • google::cloud::storage::RetryPolicyOption:這個程式庫提供 google::cloud::storage::LimitedErrorCountRetryPolicygoogle::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::StrictIdempotencyPolicygoogle::cloud::storage::AlwaysRetryIdempotencyPolicy 類別。您可以提供自己的類別,但必須實作 google::cloud::storage::IdempotencyPolicy 介面。

詳情請參閱 C++ 用戶端程式庫參考說明文件

C#

您無法自訂 C# 用戶端程式庫使用的預設重試策略。

Go

初始化儲存空間用戶端時,系統會設定預設的重試設定。除非覆寫,否則設定中的選項會設為預設值。使用者可以為單一程式庫呼叫設定非預設的重試行為 (使用 BucketHandle.RetryerObjectHandle.Retryer),也可以為用戶端發出的所有呼叫設定重試行為 (使用 Client.SetRetry)。如要修改重試行為,請將相關的 RetryOptions 傳遞至下列其中一種方法。

請參閱下列程式碼範例,瞭解如何自訂重試行為。

Java

初始化 Storage 時,系統也會初始化 RetrySettings 的執行個體。除非遭到覆寫,否則 RetrySettings 中的選項會設為預設值。如要修改預設的自動重試行為,請將自訂的 StorageRetryStrategy 傳遞至用於建構 Storage 執行個體的 StorageOptions。如要修改任何其他純量參數,請將自訂 RetrySettings 傳遞至用於建構 Storage 例項的 StorageOptions

請參閱以下範例,瞭解如何自訂重試行為:

Node.js

初始化 Cloud Storage 時,系統也會初始化 retryOptions 設定檔。除非覆寫,否則設定中的選項會設為預設值。如要修改預設的重試行為,請在初始化時,將自訂重試設定 retryOptions 傳遞至儲存空間建構函式。Node.js 用戶端程式庫可自動使用輪詢策略,重試具有 autoRetry 參數的要求。

請參閱下列程式碼範例,瞭解如何自訂重試行為。

PHP

初始化儲存空間用戶端時,系統會設定預設的重試設定。除非覆寫,否則設定中的選項會設為預設值。使用者可以透過陣列傳遞覆寫選項,為用戶端或單一作業呼叫設定非預設的重試行為。

請參閱下列程式碼範例,瞭解如何自訂重試行為。

Python

如要修改預設重試行為,請呼叫 with_BEHAVIOR 方法,建立 google.cloud.storage.retry.DEFAULT_RETRY 物件的副本。如果您加入 DEFAULT_RETRY 參數,Python 用戶端程式庫會自動使用輪詢策略重試要求。

請注意,系統不支援對物件擷取或傳送酬載資料的作業 (例如上傳和下載)。with_predicate建議逐一修改屬性。詳情請參閱 google-api-core Retry 參考資料

如要設定自己的條件式重試,請建立 ConditionalRetryPolicy 物件,並使用 DEFAULT_RETRY_IF_GENERATION_SPECIFIEDDEFAULT_RETRY_IF_METAGENERATION_SPECIFIEDDEFAULT_RETRY_IF_ETAG_IN_JSON 包裝自訂 Retry 物件。

請參閱下列程式碼範例,瞭解如何自訂重試行為。

Ruby

初始化儲存空間用戶端時,所有重試設定都會設為上表顯示的值。如要修改預設重試行為,請在初始化儲存空間用戶端時傳遞重試設定。

如要覆寫特定作業的重試次數,請在作業的 options 參數中傳遞 retries

REST API

使用「指數輪詢」演算法,實作自己的重試策略。

指數輪詢演算法

指數輪詢演算法會以指數方式重試要求,並將每次要求之間的等待時間逐漸增加至最大輪詢時間,一般來說,您應使用指數輪詢和抖動,重試符合回應和等冪條件的要求。如要瞭解如何以指數輪詢方式自動重試,請參閱解決連鎖故障問題

重試反模式

建議您視情況使用或自訂內建重試機制,詳情請參閱自訂重試。無論您是使用預設重試機制、自訂機制,還是實作自己的重試邏輯,都必須避免下列常見的反模式,因為這些模式可能會加劇問題,而非解決問題。

不輪詢就重試

立即重試要求或延遲時間很短,可能會導致連鎖性故障,也就是說,故障可能會觸發其他故障。

如何避免這個問題:實作指數輪詢並加入隨機延遲。這項策略會逐步增加重試之間的等待時間,並加入隨機元素,避免重試次數過多導致服務過載。

無條件重試非等冪作業

重複執行非冪等作業可能會導致非預期的副作用,例如非預期的資料覆寫或刪除。

如何避免這個問題:請詳閱「作業的等冪性」一節,徹底瞭解各項作業的等冪性特徵。對於非等冪運算,請確保重試邏輯可以處理潛在的重複項目,或完全避免重試。請謹慎重試,以免導致競爭狀況。

重試無法重試的錯誤

將所有錯誤視為可重試可能會造成問題。舉例來說,授權失敗或無效要求等部分錯誤會持續發生,如果未解決根本原因就重試,將無法成功,且可能導致應用程式陷入無限迴圈。

如何避免這種情況:將錯誤分為暫時性 (可重試) 和永久性 (不可重試)。請只重試暫時性錯誤,例如 4084295xx HTTP 代碼,或特定連線問題。如果是永久性錯誤,請記錄下來並妥善處理根本原因。

忽略重試次數上限

無限期重試可能會導致應用程式耗盡資源,或持續向不會自行復原的服務傳送要求。

如何避免這種情況:根據工作負載的性質調整重試次數上限。如為對延遲時間較敏感的工作負載,請考慮設定重試時間上限,確保及時回應或失敗。如果是批次工作負載,可能可以容忍暫時性伺服器端錯誤的重試時間較長,建議您設定較高的重試次數上限。

不必要地分層重試

在現有的重試機制上新增自訂應用程式層級的重試邏輯,可能會導致重試次數過多。舉例來說,如果應用程式重試作業三次,而基礎用戶端程式庫也會針對應用程式的每次嘗試重試三次,您最終可能會重試九次。如果針對無法重試的錯誤傳送大量重試要求,可能會導致要求遭到節流,進而限制所有工作負載的輸送量。重試次數過多也可能導致要求延遲,但成功率不會提高。

如何避免這種情況:建議您使用及設定內建的重試機制。如果必須實作應用程式層級的重試機制 (例如針對跨多項作業的特定商業邏輯),請務必清楚瞭解底層的重試行為。建議您在其中一個層級中停用或大幅限制重試次數,避免乘法效應。

後續步驟