共用方式為


使用 gRPC 重試的暫時性錯誤處理

注意

這不是這篇文章的最新版本。 如需目前版本,請參閱本文的 .NET 8 版本

警告

不再支援此版本的 ASP.NET Core。 如需詳細資訊,請參閱 .NET 和 .NET Core 支援原則。 如需目前版本,請參閱本文的 .NET 8 版本

重要

這些發行前產品的相關資訊在產品正式發行前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。

如需目前版本,請參閱本文的 .NET 8 版本

作者:James Newton-King

gRPC 重試這項功能,可讓 gRPC 用戶端自動重試失敗的呼叫。 本文討論如何設定重試原則,以在 .NET 中建立復原性、容錯的 gRPC 應用程式。

gRPC 重試需要 Grpc.Net.Client 2.36.0 版或更新版本。

暫時性錯誤處理

gRPC 呼叫可能會因暫時性錯誤而中斷。 暫時性錯誤包括:

  • 暫時失去網路連線。
  • 暫時無法使用服務。
  • 因伺服器載入而逾時。

當 gRPC 呼叫中斷時,用戶端會擲回 RpcException,以及錯誤的詳細資料。 用戶端應用程式必須攔截例外狀況,並選擇如何處理錯誤。

var client = new Greeter.GreeterClient(channel);
try
{
    var response = await client.SayHelloAsync(
        new HelloRequest { Name = ".NET" });

    Console.WriteLine("From server: " + response.Message);
}
catch (RpcException ex)
{
    // Write logic to inspect the error and retry
    // if the error is from a transient fault.
}

在應用程式各處複製重試邏輯的過程,非常詳細繁瑣且容易出錯。 幸運的是,.NET gRPC 用戶端有內建支援自動重試功能。

設定 gRPC 重試原則

建立 gRPC 通道時,會設定一次重試原則:

var defaultMethodConfig = new MethodConfig
{
    Names = { MethodName.Default },
    RetryPolicy = new RetryPolicy
    {
        MaxAttempts = 5,
        InitialBackoff = TimeSpan.FromSeconds(1),
        MaxBackoff = TimeSpan.FromSeconds(5),
        BackoffMultiplier = 1.5,
        RetryableStatusCodes = { StatusCode.Unavailable }
    }
};

var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions
{
    ServiceConfig = new ServiceConfig { MethodConfigs = { defaultMethodConfig } }
});

上述 程式碼:

  • 建立 MethodConfig。 您可以設定每個方法的重試原則,並使用 Names 屬性來比對方法。 這個方法已設定 MethodName.Default,因此會套用至這個通道所呼叫的所有 gRPC 方法。
  • 設定重試原則。 這個原則會指示用戶端自動重試已失敗且狀態碼為 Unavailable 的 gRPC 呼叫。
  • 藉由設定 GrpcChannelOptions.ServiceConfig,將建立的通道設定為使用重試原則。

使用通道建立的 gRPC 用戶端會自動重試失敗的呼叫:

var client = new Greeter.GreeterClient(channel);
var response = await client.SayHelloAsync(
    new HelloRequest { Name = ".NET" });

Console.WriteLine("From server: " + response.Message);

重試有效時機

系統會在下列情況下重試呼叫:

  • 失敗的狀態碼符合 RetryableStatusCodes 中的值。
  • 先前的嘗試次數少於 MaxAttempts
  • 尚未認可呼叫。
  • 尚未超過期限。

gRPC 呼叫會在兩種情境中認可:

  • 用戶端收到回應標頭。 呼叫 ServerCallContext.WriteResponseHeadersAsync 時,或當第一則訊息寫入伺服器回應資料流時,伺服器會傳送回應標頭。
  • 用戶端的外寄訊息 (若為串流,則為多則訊息) 已超過用戶端的緩衝區大小上限。 MaxRetryBufferSizeMaxRetryBufferPerCallSize 是在 通道上設定

不論狀態碼或先前的嘗試次數為何,都不會重試已認可的呼叫。

串流呼叫

串流呼叫可以搭配 gRPC 重試使用,但合併使用時有重要的考慮事項:

  • 伺服器串流雙向串流:從伺服器傳回多則訊息的串流 RPC 在收到第一則訊息之後,將不會進行重試。 應用程式必須新增額外的邏輯,才能手動重新建立伺服器串流呼叫和雙向串流呼叫。
  • 用戶端串流雙向串流:如果傳出的訊息已超過用戶端的緩衝區大小上限,則傳送多則訊息至伺服器的串流 RPC 將不會進行重試。 可以透過組態增加緩衝區大小上限。

如需詳細資訊,請參閱重試有效時機

重試輪詢延遲

各次重試嘗試之間的輪詢延遲,是使用 InitialBackoffMaxBackoffBackoffMultiplier 來設定。 如需每個選項的詳細資訊,請參閱 gRPC 重試選項一節

各次重試嘗試之間的實際延遲會隨機化。 介於 0 到目前輪詢之間的隨機延遲,會決定下次進行重試嘗試的時間。 請考慮即使已設定指數輪詢,增加各次嘗試之間的目前輪詢,各次嘗試之間的實際延遲並不一定都會變長。 系統將延遲隨機化,以防止多個呼叫的重試會叢集在一起,且可能造成伺服器多載。

使用中繼資料偵測重試

可以透過 grpc-previous-rpc-attempts 中繼資料的存在來偵測 gRPC 重試。 grpc-previous-rpc-attempts 中繼資料:

  • 會自動新增至重試的呼叫,並傳送至伺服器。
  • 值代表先前重試嘗試的數目。
  • 值一律為整數。

請考慮下列重試情節:

  1. 用戶端對伺服器進行 gRPC 呼叫。
  2. 伺服器失敗並傳回可重試的狀態碼回應。
  3. 用戶端重試 gRPC 呼叫。 因為先前曾嘗試過一次,所以 grpc-previous-rpc-attempts 中繼資料的值是 1。 中繼資料會隨著重試傳送至伺服器。
  4. 伺服器成功並傳回 OK。
  5. 用戶端回報成功。 grpc-previous-rpc-attempts 位於回應的中繼資料,且值為 1

初始 gRPC 呼叫上沒有 grpc-previous-rpc-attempts 中繼資料,第一次重試時為 1、第二次重試為 2,依此類推。

gRPC 重試選項

下表描述設定 gRPC 重試原則的選項:

選項 描述
MaxAttempts 呼叫嘗試次數上限,包括原始嘗試。 此值會受到 GrpcChannelOptions.MaxRetryAttempts 限制,預設值為 5。 此為必要的值,而且必須大於 1。
InitialBackoff 各次重試嘗試之間的初始輪詢延遲。 介於 0 到目前輪詢之間的隨機延遲,會決定下次進行重試嘗試的時間。 每次嘗試之後,目前的輪詢都會乘以 BackoffMultiplier。 此為必要的值,而且必須大於零。
MaxBackoff 最大輪詢會對指數輪詢成長設定上限。 此為必要的值,而且必須大於零。
BackoffMultiplier 每次重試嘗試之後,輪詢都會乘上這個值,並且當乘數大於 1 時,會以指數方式成長。 此為必要的值,而且必須大於零。
RetryableStatusCodes 狀態碼的集合。 系統會自動重試在失敗時狀態相符的 gRPC 呼叫。 如需狀態碼的詳細資訊,請參閱狀態碼及其在 gRPC 中的使用。 至少需要一個可重試的狀態碼。

對沖

對沖是替代的重試策略。 對沖可讓您主動傳送單一 gRPC 呼叫的多個複本,而不需要等待回應。 對沖的 gRPC 呼叫可能會在伺服器上多次執行,而系統會使用第一個成功的結果。 請務必只針對能安全多次執行而不會產生負面影響的方法啟用對沖。

與重試相比,對沖的優缺點如下:

  • 對沖的優點是,可能會較快傳回成功的結果。 它允許系統同時呼叫多個 gRPC,並在得到第一個成功的結果時完成。
  • 對沖的缺點是可能造成浪費。 可能進行多次呼叫,且全數成功。 只有第一個結果獲得採用,而 rest 遭到捨棄。

設定 gRPC 對沖原則

對沖原則的設定類似於重試原則。 請注意,對沖原則無法與重試原則結合。

var defaultMethodConfig = new MethodConfig
{
    Names = { MethodName.Default },
    HedgingPolicy = new HedgingPolicy
    {
        MaxAttempts = 5,
        NonFatalStatusCodes = { StatusCode.Unavailable }
    }
};

var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions
{
    ServiceConfig = new ServiceConfig { MethodConfigs = { defaultMethodConfig } }
});

gRPC 對沖選項

下表描述設定 gRPC 對沖原則的選項:

選項 描述
MaxAttempts 對沖原則所傳送的呼叫數目最大值。 MaxAttempts 代表所有嘗試的總數,包括原始嘗試在內。 此值會受到 GrpcChannelOptions.MaxRetryAttempts 限制,預設值為 5。 此為必要的值,而且必須大於或等於 2。
HedgingDelay 系統會立即傳送第一個呼叫,後續的對沖呼叫則依據這個值加以延遲。 當延遲設定為零或 null 時,系統會立即傳送所有對沖呼叫。 HedgingDelay 是選擇項,預設值為零。 此值必須大於或等於零。
NonFatalStatusCodes 狀態碼的集合,表示其他對沖呼叫仍然可能成功。 如果伺服器傳回不嚴重的狀態碼,系統會繼續執行對沖呼叫。 否則,系統會取消等待處理的要求,並將錯誤傳回給應用程式。 如需狀態碼的詳細資訊,請參閱狀態碼及其在 gRPC 中的使用

其他資源