为了保障系统的稳定和安全,在调用三方服务时,可以增加重试和熔断。重试是调用一次失败后再试几试,避免下游服务一次闪断,就把整个链路终止;熔断是为了防止太多的次数的无效访问,导致系统不可知异常。
Polly是独立的重试机制的三方库,这里只说明在使用httpclient时,请求下游api时的重试和熔断。需要引入NuGet包Microsoft.Extensions.Http.Polly。
先看一个简单的重试
using Polly; var builder = WebApplication.CreateBuilder(args); builder.Services .AddHttpClient("RetryClient", httpclient => { httpclient.BaseAddress = new Uri("http://localhost:5258"); }) .AddTransientHttpErrorPolicy(policyBuilder => policyBuilder.RetryAsync(3)); var app = builder.Build(); //调用httpclient app.MapGet("/test", async (IHttpClientFactory httpClientFactory) => { try { var httpClient = httpClientFactory.CreateClient("RetryClient"); var content = await httpClient.GetStringAsync("other-api"); Console.WriteLine(content); return "ok"; } catch (Exception exc) { if (!Count.Time.HasValue) { Count.Time = DateTime.Now; } return $"{exc.Message} 【次数:{Count.I++}】 【{Count.Time.Value.ToString("yyyy-MM-dd HH:mm:ss.fffffff")}】"; } }); //被调用的接口,返回状态码500 app.MapGet("/other-api", (ILogger<Program> logger) => { logger.LogInformation($"失败:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fffffff")}"); return Results.StatusCode(500); }); app.Run(); static class Count { public static int I = 1; public static DateTime? Time; }
返回的结果:
通过AddTransientHttpErrorPolicy(policyBuilder => policyBuilder.RetryAsync(3));我们让请求进行了3次重试,加上原本的一次,就是4次请求。在红色框时,会发现请求集中在极短的时间内,如果下游服务有故障,可能不会在这么短的时间内自动恢复,更好的做法是:根据重试的次数,来延长(或随机,或自建延时算法)请求的时间,比如:
.AddTransientHttpErrorPolicy(policyBuilder => policyBuilder.WaitAndRetryAsync(3, retryNumber => { switch (retryNumber) { case 1: return TimeSpan.FromMilliseconds(500); case 2: return TimeSpan.FromMilliseconds(1000); case 3: return TimeSpan.FromMilliseconds(1500); default: return TimeSpan.FromMilliseconds(100); } }));
这时的结果如下,基本按照我们设置的时间来重试的:
还有几种重试策略,如下:
//一直重试 .AddTransientHttpErrorPolicy(policyBuilder => policyBuilder.RetryForeverAsync()); //每2秒重试一次 .AddTransientHttpErrorPolicy(policyBuilder => policyBuilder.WaitAndRetryForeverAsync(retryNumber => { Console.WriteLine(retryNumber); return TimeSpan.FromSeconds(2); })); //在5秒内4次请求,如果50%失败,就熔断10秒 .AddTransientHttpErrorPolicy(policyBuilder => policyBuilder.AdvancedCircuitBreakerAsync(0.5d, TimeSpan.FromSeconds(5), 4, TimeSpan.FromSeconds(10)));
熔断是保护服务的手段,在本例中具体用法如下:
builder.Services .AddHttpClient("RetryClient", httpclient => { httpclient.BaseAddress = new Uri("http://localhost:5258"); }) .AddTransientHttpErrorPolicy(policyBuilder => policyBuilder.WaitAndRetryAsync(3, retryNumber => { switch (retryNumber) { case 1: return TimeSpan.FromMilliseconds(500); case 2: return TimeSpan.FromMilliseconds(1000); case 3: return TimeSpan.FromMilliseconds(1500); default: return TimeSpan.FromMilliseconds(100); } })) //熔断 .AddTransientHttpErrorPolicy(policyBuilder => policyBuilder.CircuitBreakerAsync(6, TimeSpan.FromSeconds(30)));
CircuitBreaker控制如果有6次失败的请求,就暂停30秒,具体提示如下:
想要更快更方便的了解相关知识,可以关注微信公众号
标签:MiniAPI,AddTransientHttpErrorPolicy,FromMilliseconds,return,TimeSpan,重试,NET6,pol From: https://www.cnblogs.com/axzxs2001/p/16936701.html