使用 IHttpClientFactory 和 Polly 原則以指數輪詢實作 HTTP 呼叫重試

提示

本內容節錄自《容器化 .NET 應用程式的 .NET 微服務架構》(.NET Microservices Architecture for Containerized .NET Applications) 電子書,可以在 .NET Docs 上取得,或免費下載可供離線閱讀的 PDF。

.NET Microservices Architecture for Containerized .NET Applications eBook cover thumbnail.

使用指數輪詢重試的建議方法是利用更進階的 .NET 程式庫,例如開放原始碼 Polly 程式庫

Polly 是 .NET 程式庫,提供恢復功能和暫時性錯誤處理功能。 您可以藉由套用重試、斷路器、艙壁隔離 (Bulkhead Isolation)、逾時和後援等 Polly 原則,來實作這些功能。 Polly 以 .NET Framework 4.x 與 .NET Standard 1.0、1.1 和 2.0 (其支援 .NET Core 和更新版本) 為目標。

下列步驟示範如何透過整合到 IHttpClientFactory 中的 Polly 使用 HTTP 重試,如上一節所述。

安裝 .NET 套件

首先,您需要安裝 Microsoft.Extensions.Http.Polly 套件。

參考 .NET 8 套件

自 .NET Core 2.1 後提供 IHttpClientFactory,不過,建議您在專案中使用 NuGet 中的最新 .NET 8 套件。 您通常也需要參考延伸模組套件 Microsoft.Extensions.Http.Polly

在應用程式啟動時,使用 Polly 的重試原則來設定用戶端

AddPolicyHandler() 方法會將原則新增至您將使用的 HttpClient 物件。 在此案例中,它會為使用指數輪詢的 HTTP 重試新增 Polly 原則。

為了有更模組化的方法,可在 Program.cs 檔案內的個別方法中定義 Http 重試原則,如下列程式碼所示:

static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
    return HttpPolicyExtensions
        .HandleTransientHttpError()
        .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound)
        .WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2,
                                                                    retryAttempt)));
}

如前幾節所示,您必須在標準 Program.cs 應用程式組態中定義具名或具類型的用戶端 HttpClient 設定。 現在,您可以新增累加程式碼,以使用指數輪詢來指定 HTTP 重試的原則,如下所示:

// Program.cs
builder.Services.AddHttpClient<IBasketService, BasketService>()
        .SetHandlerLifetime(TimeSpan.FromMinutes(5))  //Set lifetime to five minutes
        .AddPolicyHandler(GetRetryPolicy());

透過 Polly,您可以定義重試原則,其中包含重試次數、指數輪詢組態,以及發生 HTTP 例外狀況時所要採取的動作,例如記錄錯誤。 在本例中,會設定原則,以便使用指數重試嘗試六次,一開始每隔兩秒。

將 Jitter 策略新增至重試原則

如果發生高並行和高可擴縮性以及高競爭的情況,則定期重試原則可能會影響您的系統。 若要解決在部分中斷時來自許多用戶端的類似重試達到最高的問題,一個很好的解決方法是將 Jitter 策略新增至重試演算法/原則。 此策略可改善端對端系統的整體效能。 如 Polly:使用 Jitter 重試 (英文) 所建議,可透過順暢且平均分配的重試間隔,並在指數輪詢上套用妥善控制的中位數初始重試延遲,來實作良好的 Jitter 策略。 此方法有助於在問題發生時分散峰值。 下列=範例會說明這個準則:


var delay = Backoff.DecorrelatedJitterBackoffV2(medianFirstRetryDelay: TimeSpan.FromSeconds(1), retryCount: 5);

var retryPolicy = Policy
    .Handle<FooException>()
    .WaitAndRetryAsync(delay);

其他資源