微服务熔断,降级
微服务的分层方式:
以文件拆分为主,程序集拆分位次
虽然Consul有健康检查 但是健康检查是设置间隔时间的如果是10秒,在十秒内服务出现问题就会出现请求的压积,所以我们需要解决这个问题就需要熔断限流的操作
那么什么是熔断呢?
熔断就是在被调用端出现宕机,和超时两种情况出现的一种策略应对机制。
熔断就好比保险丝,我们先来看一看保险丝的情况
客户端请求服务端不需要直接请求服务端,并且请求到熔断器;熔断器类似保险丝;
为什么使用熔断,防止某个微服务宕机,所有集聚在这个微服务上的请求就会积压不断尝试,从而导致集合微服务的性能急剧下降,这个需要我们就需要使用熔断工具保证系统的性能和稳定了:
服务调用出现异常(包括超时和宕机两种情况)
? 如果服务连续几次都出现异常,那么就将服务进行熔断一段时间,
什么是降级?相当于添加一个或者多个备胎
为什么要使用降级
1、服务主动降级(选择性放弃)
? 主动将服务进行进行异常返回
? 2、服务异常降级
? 如果服务调用出现超时或者宕机的情况,就按照自定义的策略进行返回。
项目中熔断降级的目的是保证系统的弹性,使系统高可用
熔断直接抛出异常,让后降级步获异常,返回合理的信息
polly熔断原理:步获异常根据异常返回自己包装的异常:
降级的原理:
熔断和降级的本质就是 异常的步获和异常的处理;
项目中如何运用熔断降级:
熔断降级工具
? 1、Polly
? 2、Hystrix
微服务中如何使用Polly
主要功能(五种策略)
? 重试(Retry)
? 断路器(Circuit-breaker)
? 超时检测(Timeout)
? 缓存(Cache)
? 降级(FallBack)
Polly官网地址
? http://www.thepollyproject.org/
Polly安装
? Nuget Microsoft.Extensions.Http.Polly
Polly如何使用
? 条件
? 1、微服务项目
? 2、Polly
? 3、Polly http扩展
? 步骤
? 1、先通过nuget进行安装
? Microsoft.Extensions.Http.Polly
? 2、然后在HttpClient后面添加扩展方法AddPolicyHandler()
? 3、然后在团队服务里面,测试宕机,和超时情况
? 4、先选择熔断策略(在Startup中的 ConfigureServices中)
//熔断机制 3代表出现多少次异常开启熔断, 开始时间, 处理的异常,开启的时间 ,熔断机制 就是一个 try catch
.AddPolicyHandler(Policy.Handle ().CircuitBreakerAsync(3, TimeSpan.FromSeconds(10), (ex, ts) => { Console.WriteLine($"服务{name}断路器开启,异常消息:{ex.Exception.Message}"); Console.WriteLine($"服务{name}断路器开启时间:{ts.TotalSeconds}s"); }, () => { Console.WriteLine($"服务{name}断路器重置"); }, () => { Console.WriteLine($"服务{name}断路器半开启(一会开,一会关)"); }))
? 5、然后选择降级策略
//自定义异常处理(用缓存处理
var fallbackResponse = new HttpResponseMessage { Content = new StringContent("系统出现异常,请稍后重试"), StatusCode = HttpStatusCode.GatewayTimeout }; .AddPolicyHandler(Policy.HandleInner ().FallbackAsync(options.httpResponseMessage, async b => { // 1、降级打印异常 Console.WriteLine($"服务{name}开始降级,异常消息:{b.Exception.Message}"); // 2、降级后的数据 Console.WriteLine($"服务{name}降级内容响应:{options.httpResponseMessage.Content.ToString()}"); await Task.CompletedTask; }))
6、然后选择重试策略
.AddPolicyHandler(Policy.Handle () .RetryAsync(options.RetryCount) )
? 7、最后选择超时机制
.AddPolicyHandler(Policy.TimeoutAsync(TimeSpan.FromSeconds(options.TimeoutTime)));
我们在集合服务种添加polly 的nuget包
Startup.cs 代码演示:
public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { // 1、自定义异常处理(用缓存处理) var fallbackResponse = new HttpResponseMessage { Content = new StringContent("系统正繁忙,请稍后重试"),// 内容,自定义内容 StatusCode = HttpStatusCode.GatewayTimeout // 504 }; //services.AddHttpClient().AddHttpClientConsul(); #region polly配置(未封装) { //services.AddHttpClient("mrico") //// 1.1 降级(捕获异常,进行自定义处理) //.AddPolicyHandler(Policy.Handle //{ // // 1、降级打印异常 // Console.WriteLine($"开始降级,异常消息:{b.Exception.Message}"); // // 2、降级后的数据 // //Console.WriteLine($"降级内容响应:{}"); // await Task.CompletedTask; //})) //// 1.2 熔断机制 //.AddPolicyHandler(Policy().FallbackAsync(fallbackResponse, async b => .Handle //{ // Console.WriteLine($"断路器开启,异常消息:{ex.Exception.Message}"); // Console.WriteLine($"断路器开启时间:{ts.TotalSeconds}s"); //}, () => //{ // Console.WriteLine($"断路器重置"); //}, () => //{ // Console.WriteLine($"断路器半开启(一会开,一会关)"); //})) //// 1.3 失败重试 //.AddPolicyHandler(Policy().CircuitBreakerAsync(3, TimeSpan.FromSeconds(10), (ex, ts) => // .Handle () // .RetryAsync(3) //) ////1.4、超时 //.AddPolicyHandler(Policy.TimeoutAsync(TimeSpan.FromSeconds(2))); } #endregion // 1.2 封装之后的调用PollyHttpClient services.AddPollyHttpClient("mrico", options => { options.TimeoutTime = 1; // 1、超时时间 options.RetryCount = 3;// 2、重试次数 options.CircuitBreakerOpenFallCount = 2;// 3、熔断器开启(多少次失败开启) options.CircuitBreakerDownTime = 100;// 4、熔断器开启时间 options.httpResponseMessage = fallbackResponse;// 5、降级处理 }) // 2、consul封装 .AddHttpClientConsul(); /*// 2、注册consul服务发现 services.AddConsulDiscovery(); // 3、注册负载均衡 services.AddSingleton (); */ // 4、注册team服务 services.AddSingleton(); services.AddControllers(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } }
封装:
////// HttpClient熔断降级策略选项 /// public class PollyHttpClientOptions { /// /// 超时时间设置,单位为秒 /// public int TimeoutTime { set; get; } /// /// 失败重试次数 /// public int RetryCount { set; get; } /// /// 执行多少次异常,开启短路器(例:失败2次,开启断路器) /// public int CircuitBreakerOpenFallCount { set; get; } /// /// 断路器开启的时间(例如:设置为2秒,短路器两秒后自动由开启到关闭) /// public int CircuitBreakerDownTime { set; get; } /// /// 降级处理(将异常消息封装成为正常消息返回,然后进行响应处理,例如:系统正在繁忙,请稍后处理.....) /// public HttpResponseMessage httpResponseMessage { set; get; } } /// /// 微服务中HttpClient熔断,降级策略扩展 /// public static class PollyHttpClientServiceCollectionExtensions { /// /// Httpclient扩展方法 /// /// ioc容器 /// HttpClient 名称(针对不同的服务进行熔断,降级) /// 熔断降级配置 /// 降级处理错误的结果 /// public static IServiceCollection AddPollyHttpClient(this IServiceCollection services, string name,Action action) { // 1、创建选项配置类 PollyHttpClientOptions options = new PollyHttpClientOptions(); action(options); // 2、配置httpClient,熔断降级策略 services.AddHttpClient(name) //1.1 降级策略 .AddPolicyHandler(Policy .HandleInner ().FallbackAsync(options.httpResponseMessage, async b => { // 1、降级打印异常 Console.WriteLine($"服务{name}开始降级,异常消息:{b.Exception.Message}"); // 2、降级后的数据 Console.WriteLine($"服务{name}降级内容响应:{options.httpResponseMessage.Content.ToString()}"); await Task.CompletedTask; })) // 1.2 断路器策略 .AddPolicyHandler(Policy .Handle ().CircuitBreakerAsync(options.CircuitBreakerOpenFallCount, TimeSpan.FromSeconds(options.CircuitBreakerDownTime), (ex, ts) => { Console.WriteLine($"服务{name}断路器开启,异常消息:{ex.Exception.Message}"); Console.WriteLine($"服务{name}断路器开启时间:{ts.TotalSeconds}s"); }, () => { Console.WriteLine($"服务{name}断路器关闭"); }, () => { Console.WriteLine($"服务{name}断路器半开启(时间控制,自动开关)"); })) // 1.3 重试策略 .AddPolicyHandler(Policy .Handle () .RetryAsync(options.RetryCount) ) // 1.4 超时策略 .AddPolicyHandler(Policy.TimeoutAsync (TimeSpan.FromSeconds(options.TimeoutTime))); return services; } }