Spiga

微服务架构(二):熔断降级

2018-03-15 20:56:36

概念------为什么-----如何使用----运行原理------熔断-----降级-----超时------重试----封装 -----consul和polly整合到项目中

首先我们来明确一下,微服务架构的基本单位是微服务,也就主体是微服务----同时每一个微服务都有自己的结构。这些结构组合成了一个微服务(这属于文件夹分层发)这个时候,那么每一个微服务都会出现相同的结构。这个时候很多同学会有疑问,为什么各个微服务之间这些相同的文件不能够进行通用呢,反而会出现这么多冗余。这样做的原因,1、保证微服务的独立性,2、保证微服务的稳定。我举个例子:微服务就好比我们每一个人,我们每一个人就组成了一个社会架构,微服务和这种场景是类似的。大家都知道,每个人的结构都是一样的。如果每个人结构都全部集中到一起。会出现什么问题,大家可以想象一下。全部乱套了。同理,微服务也是一样。所有微服务的第一要务就是保证独立性。所以我这里对微服务采用文件夹分层法。

对于什么时候用程序集分层。先明白一下,每一个微服务都有自己的领域模型(也就是我们昨天说的问题和问题边界)。如果多个微服务之间。存在不得不共享资源,共享资源是不易变化,且变化不影响每一个微服务的逻辑的时候。那么我们就把这通用的逻辑抽取出来,用dll来分层进行引用,例如:微服务之间都需要通信,需要认证,需要限流,负载均衡等等。那么咱们就把这一层称作为工具层。

什么是熔断

熔断就是在被调用端出现宕机,和超时两种情况出现的一种策略应对机制。

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

为什么要使用熔断

  1. 服务调用出现异常(包括超时和宕机两种情况)
    如果服务连续几次都出现异常,那么就将服务进行熔断一段时间,
  2. 服务调用出现异常(包括超时和宕机两种情况) 如果服务连续几次都出现异常,那么就将服务进行熔断一段时间
  3. 服务调用出现异常(包括超时和宕机两种情况)
    如果服务连续几次都出现异常,那么就将服务进行熔断一段时间

什么是降级

为什么要使用降级

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

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

  2. 服务异常降级

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

  3. 服务主动降级(选择性放弃)

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

  4. 服务异常降级

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

  5. 服务主动降级(选择性放弃)

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

  6. 服务异常降级

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

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

项目中如何运用熔断降级

熔断降级工具

  1. Polly
  2. Hystrix

微服务中如何使用Polly

主要功能

重试(Retry)

断路器(Circuit-breaker)

超时检测(Timeout)

缓存(Cache)

降级(FallBack)

重试(Retry)

断路器(Circuit-breaker)

超时检测(Timeout)

缓存(Cache)

降级(FallBack)
重试(Retry)

断路器(Circuit-breaker)

超时检测(Timeout)

缓存(Cache)

降级(FallBack)

Polly官网地址

http://www.thepollyproject.org/

http://www.thepollyproject.org/
http://www.thepollyproject.org/

Polly安装

Nuget Microsoft.Extensions.Http.Polly

Nuget Microsoft.Extensions.Http.Polly
Nuget Microsoft.Extensions.Http.Polly

Polly如何使用

条件

  1. 微服务项目
  2. Polly
  3. Polly http扩展

步骤

  1. 先通过nuget进行安装
    Microsoft.Extensions.Http.Polly
  2. 然后在HttpClient后面添加扩展方法AddPolicyHandler()
  3. 然后在团队服务里面,测试宕机,和超时情况
  4. 先选择熔断策略

条件

  1. 微服务项目
  2. Polly
  3. Polly http扩展

步骤

  1. 先通过nuget进行安装
    Microsoft.Extensions.Http.Polly
  2. 然后在HttpClient后面添加扩展方法AddPolicyHandler()
  3. 然后在团队服务里面,测试宕机,和超时情况
  4. 先选择熔断策略
    条件
  5. 微服务项目
  6. Polly
  7. Polly http扩展

步骤

  1. 先通过nuget进行安装
    Microsoft.Extensions.Http.Polly
  2. 然后在HttpClient后面添加扩展方法AddPolicyHandler()
  3. 然后在团队服务里面,测试宕机,和超时情况
  4. 先选择熔断策略
.AddPolicyHandler(Policy<HttpResponseMessage>.Handle<Exception>().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}断路器半开启(一会开,一会关)");
            }))
  1. 然后选择降级策略
var fallbackResponse = new HttpResponseMessage
{
    Content = new StringContent("系统出现异常,请稍后重试"),
    StatusCode = HttpStatusCode.GatewayTimeout
};

.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. 然后选择重试策略
.AddPolicyHandler(Policy<HttpResponseMessage>
              .Handle<Exception>()
              .RetryAsync(options.RetryCount)
            )
  1. 最后选择超时机制
.AddPolicyHandler(Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(options.TimeoutTime)));

Polly如何在项目中封装

条件

  1. IServiceCollection扩展类
  2. HttpClientPolly选项类

步骤

  1. 创建PollyHttpClientServiceCollectionExtensions类

条件

  1. IServiceCollection扩展类
  2. HttpClientPolly选项类

步骤

  1. 创建PollyHttpClientServiceCollectionExtensions类
    条件
  2. IServiceCollection扩展类
  3. HttpClientPolly选项类

步骤

  1. 创建PollyHttpClientServiceCollectionExtensions类
/// <summary>
        /// Httpclient扩展方法
        /// </summary>
        /// <param name="services">ioc容器</param>
        /// <param name="name">HttpClient 名称(针对不同的服务进行熔断,降级)</param>
        /// <param name="action">熔断降级配置</param>
        /// <param name="TResult">降级处理错误的结果</param>
        /// <returns></returns>
        public static IServiceCollection AddHttpClientPolly(this IServiceCollection services,string name,Action<HttpClientPollyOptions> action)
        {
            // 1、创建选项配置类
            HttpClientPollyOptions options = new HttpClientPollyOptions();
            action(options);
       // 2、配置httpClient,熔断降级策略
        services.AddHttpClient(name)
       //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;
    }
  1. 然后创建熔断,降级,重试,超时HttpClientPollyOptions配置类
/// <summary>
        /// 超时时间设置,单位为秒
        /// </summary>
        public int TimeoutTime { set; get; }
    /// <summary>
    /// 失败重试次数
    /// </summary>
    public int RetryCount { set; get; }

    /// <summary>
    /// 执行多少次异常,开启短路器(例:失败2次,开启断路器)
    /// </summary>
    public int CircuitBreakerOpenFallCount { set; get; }

    /// <summary>
    /// 断路器开启的时间(例如:设置为2秒,短路器两秒后自动由开启到关闭)
    /// </summary>
    public int CircuitBreakerDownTime { set; get; }

    /// <summary>
    /// 降级处理(将异常消息封装成为正常消息返回,然后进行响应处理,例如:系统正在繁忙,请稍后处理.....)
    /// </summary>
    public HttpResponseMessage httpResponseMessage { set; get; }
  1. 封装后的代码调用
services.AddPollyHttpClient("tony",options => {
    options.TimeoutTime = 1;
    options.RetryCount = 3;
    options.CircuitBreakerOpenFallCount = 2;
    options.CircuitBreakerDownTime = 100;
    options.httpResponseMessage = fallbackResponse;
});