通过应用 Polly 策略(如重试、断路、隔离、超时和回退)即可实现这些功能。
断路:当系统出错的次数超过了指定的阈值,就要中断当前线路,等待一段时间后再继续。
隔离:将可控的操作限制在一个固定大小的资源池中,以隔离有潜在可能相互影响的操作。
HttpMessageHandler 实例,该实例具有上面提到的“套接字耗尽”和 DNS 更改问题 。
它还提供基于 Polly 的中间件的扩展,以利用 HttpClient 中的委托处理程序。
使用 IHttpClientFactory 的好处
IHttpClientFactory 当前实现具有以下优势:
- 例如,可以配置预配置的客户端(服务代理)以访问特定微服务。
- 通过后列方式整理出站中间件的概念:在
HttpClient中委托处理程序并实现基于 Polly 的中间件以利用 Polly 的复原策略。 - 将 HTTP 客户端注册到工厂后,可使用一个 Polly 处理程序将 Polly 策略用于重试、断路器等。
- HttpMessageHandler 的生存期,避免在自行管理
HttpClient生存期时出现上述问题。
事实上,注入的 HttpClient 实例是从 DI 角度区分范围的 。
IHttpClientFactory (DefaultHttpClientFactory) 实现与 Microsoft.Extensions.DependencyInjection NuGet 包中的 DI 实现紧密关联。
结合使用类型化客户端和 IHttpClientFactory
此配置可以包括特定值,如基本服务器、HTTP 标头或超时。
HttpMessageHandler 对象)获取自池,可供从工厂返回的 HttpClient 使用。
IHttpClientBuilder 上调用 SetHandlerLifetime(),如以下代码所示:
//Set 5 min as the lifetime for the HttpMessageHandler objects in the pool used for the Catalog Typed Client services.AddHttpClient<ICatalogService, CatalogService>() .SetHandlerLifetime(TimeSpan.FromMinutes(5));
还可以在注册中添加特定于实例的配置(例如,配置基址),并添加一些弹性策略,
services.AddHttpClient<ICatalogService, CatalogService>(client => { client.BaseAddress = new Uri(Configuration["BaseUrl"]); }) .AddPolicyHandler(GetRetryPolicy()) .AddPolicyHandler(GetCircuitBreakerPolicy()); static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy() { return HttpPolicyExtensions .HandleTransientHttpError() .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound) .WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); }
GetRetryPolicy 用到了Microsoft.Extensions.Http.Polly 扩展包
IHttpClientFactory允许你用命名的方式来配置和使用 HttpClient。
services.AddHttpClient("GitHub", client => { client.BaseAddress = new Uri("https://api.github.com/"); client.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json"); }) .AddTransientHttpErrorPolicy(builder => builder.WaitAndRetryAsync(new[] { TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10) })); public class MyController : Controller { private readonly IHttpClientFactory _httpClientFactory; public MyController(IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; } public Task<IActionResult> SomeAction() { var client = _httpClientFactory.CreateClient("GitHub"); return Ok(await client.GetStringAsync("/someapi")); } }
AddTransientHttpErrorPolicy方法也可以从Polly的一个扩展包Polly.Extensions.Http中得到
Polly还提供了策略注册池,它相当于策略的存储中心,被注册的策略可以让你在应用程序的多个位置重用。AddPolicyHandler的一个重载方法允许您从注册池中选择策略。
var registry = services.AddPolicyRegistry(); registry.Add("defaultretrystrategy", HttpPolicyExtensions.HandleTransientHttpError().WaitAndRetryAsync(/* etc */)); registry.Add("defaultcircuitbreaker", HttpPolicyExtensions.HandleTransientHttpError().CircuitBreakerAsync(/* etc */)); services.AddHttpClient(/* etc */) .AddPolicyHandlerFromRegistry("defaultretrystrategy") .AddPolicyHandlerFromRegistry("defaultcircuitbreaker");
将抖动策略添加到重试策略
这样在出现问题时可以分散峰值。
Random jitterer = new Random(); var retryWithJitterPolicy = HttpPolicyExtensions .HandleTransientHttpError() .OrResult(msg => msg.StatusCode == System.Net.HttpStatusCode.NotFound) .WaitAndRetryAsync(6, // exponential back-off plus some jitter retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)) + TimeSpan.FromMilliseconds(jitterer.Next(0, 100)) );