通过 IHttpClientFactory 和 Polly 策略实现使用指数退避算法的 HTTP 调用重试

提示

此内容摘自电子书《适用于容器化 .NET 应用程序的 .NET 微服务体系结构》,可在 .NET 文档上获取,也可作为免费可下载的 PDF 脱机阅读。

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

建议的使用指数退避算法的重试方法是利用更高级的 .NET 库,如开放源 Polly 库。

Polly 是一个 .NET 库,提供恢复能力和瞬态故障处理功能。 通过应用 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 的重试策略在应用程序启动中配置客户端

将策略添加至将要使用的 HttpClient 对象需要使用 AddPolicyHandler() 方法。 在此示例中,将使用指数退避算法为 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 异常时要采取的操作,例如记录错误。 在此示例中,该策略配置为尝试 6 次(采用指数重试),以 2 秒为起始值。

将抖动策略添加到重试策略

在高并发率、高可伸缩性和高争用的情况下,常规重试策略可能会对系统产生影响。 在部分运行中断时,可能会有许多客户端同时发出相似的重试操作,从而形成操作高峰,为避免这种情况,一个好办法是向重试算法或策略中添加抖动策略。 该策略可以改进端到端系统的整体性能。 如 Polly:重试与抖动中所建议,一个好的抖动策略可以通过采用均匀分布的平滑重试间隔并在指数退避上应用一个控制良好的中值初始重试延迟来实现。 这种方法有助于在出现问题时分散峰值。 以下示例说明了这一原理:


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

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

其他资源