微服务架构:使用Polly实现熔断、降级

参考:

熔断降级--参考文档

Polly官网地址

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

Polly 和 IHttpClientFactory一起使用

HttpClientFactory 结合 Polly 轻松实现重试机制

 

熔断

熔断就是在被调用端出现宕机(死机 / 断开),和超时两种情况出现的一种策略应对机制,直接抛异常。

只断开某一服务功能,也为了防止影响其他服务的整体运行。

熔断就好比保险丝,我们先来看一看保险丝的情况

举例:家里电器短路了只有家里跳闸了,而不影响整栋楼的电路。

为什么要使用熔断

1、服务调用出现异常(包括超时和宕机两种情况)

如果服务连续几次都出现异常,那么就将服务进行熔断一段时间,程序知道这个服务是熔断状态就暂时不连接它,避免影响这个系统性能。

降级

保证核心功能可用,放弃一些非核心的外围功能减压,例如返回“系统繁忙”提示

例如:电商系统中高峰期访问压力过大时,保证购物车和支付功能可用,暂停后面还有的请求(直接返回系统繁忙),或者暂停一些浏览功能

1、服务主动降级(选择性放弃)

主动将服务进行进行异常返回

2、服务异常降级

如果服务调用出现超时或者宕机的情况,就按照自定义的策略进行返回。

项目中熔断降级的目的是保证系统的弹性,使系统高可用

熔断与降级区别

参考:

熔断与降级的区别

服务的熔断和降级的区别

熔断是直接抛异常,降级是返回自定义信息。

熔断是针对单一服务,降级是为了整个系统稳定而减少请求或者暂停外围非核心服务

Polly主要功能

重试(Retry)

断路器(Circuit-breaker)

超时检测(Timeout)

缓存(Cache)

降级(FallBack)

Polly使用步骤

1 nuget包安装

先通过nuget进行安装,在AggregateService(聚合服务)、MicroService.Core(核心层/公共层/工具层)都需要安装:Microsoft.Extensions.Http.Polly

2 添加Polly扩展类和方法

然后在HttpClient后面添加扩展方法AddPolicyHandler()

在MicroService.Core(核心服务/公共服务/工具层)中添加类

   /// <summary>
   /// 微服务中HttpClient熔断,降级策略扩展
   /// </summary>
   public static class PollyHttpClientServiceCollectionExtensions
   {
        /// <summary>
        /// Httpclient扩展Polly方法
        /// </summary>
        /// <param name="services">ioc容器</param>
        /// <param name="name">HttpClient 名称(针对不同的服务进行熔断,降级)</param>
        /// <param name="action">熔断降级配置</param>
        /// <param name="TResult">降级处理错误的结果</param>
        /// <returns></returns>
        public static IServiceCollection AddPollyHttpClient(this IServiceCollection services, string name,Action<PollyHttpClientOptions> action)
        {
            // 1、创建选项配置类
            PollyHttpClientOptions options = new PollyHttpClientOptions();
            action(options);

            // 2、配置httpClient,熔断降级策略
            services.AddHttpClient(name,client => {
                client.Timeout = TimeSpan.FromSeconds(60);
            })
           //1.1 降级策略
           .AddPolicyHandler(Policy<HttpResponseMessage>.HandleInner<Exception>().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<HttpResponseMessage>.Handle<Exception>().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<HttpResponseMessage>
              .Handle<Exception>()
              .RetryAsync(options.RetryCount)
            )
            // 1.4 超时策略
            .AddPolicyHandler(Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(options.TimeoutTime)));
            
            return services;
        }
    }

 

3 使用Polly方法

在聚合服务的Startup类的ConfigureServices中测试宕机,和超时情况

            // 1、自定义异常处理(用缓存处理)
            var fallbackResponse = new HttpResponseMessage
            {
                Content = new StringContent("系统正繁忙,请稍后重试"),// 内容,自定义内容
                StatusCode = HttpStatusCode.GatewayTimeout // 504
            };

            // 1.2 封装之后的调用PollyHttpClient
            services.AddPollyHttpClient("mrico", options => {
                options.TimeoutTime = 60; // 1、超时时间
                options.RetryCount = 3;// 2、重试次数
                options.CircuitBreakerOpenFallCount = 2;// 3、熔断器开启(多少次失败开启)
                options.CircuitBreakerDownTime = 100;// 4、熔断器开启时间
                options.httpResponseMessage = fallbackResponse;// 5、降级处理
            })
             .AddHttpClientConsul<ConsulHttpClient>(); // 1.3、HttpClient下consul封装(实现负载均衡请求)

 

posted @ 2020-08-23 20:29  日积月累码农  阅读(815)  评论(2编辑  收藏  举报