微服务的分层方式:

以文件拆分为主,程序集拆分位次

服务熔断计数统计实现 java 熔断 微服务_断路器

 


 虽然Consul有健康检查 但是健康检查是设置间隔时间的如果是10秒,在十秒内服务出现问题就会出现请求的压积,所以我们需要解决这个问题就需要熔断限流的操作

那么什么是熔断呢?

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

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

客户端请求服务端不需要直接请求服务端,并且请求到熔断器;熔断器类似保险丝;

服务熔断计数统计实现 java 熔断 微服务_自定义_02

 

为什么使用熔断,防止某个微服务宕机,所有集聚在这个微服务上的请求就会积压不断尝试,从而导致集合微服务的性能急剧下降,这个需要我们就需要使用熔断工具保证系统的性能和稳定了:

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

如果服务连续几次都出现异常,那么就将服务进行熔断一段时间,

服务熔断计数统计实现 java 熔断 微服务_服务熔断计数统计实现 java_03

 

 什么是降级?相当于添加一个或者多个备胎

服务熔断计数统计实现 java 熔断 微服务_断路器_04

 

为什么要使用降级

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

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

2、服务异常降级

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

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

服务熔断计数统计实现 java 熔断 微服务_服务熔断计数统计实现 java_05

 

 熔断直接抛出异常,让后降级步获异常,返回合理的信息

polly熔断原理:步获异常根据异常返回自己包装的异常:

服务熔断计数统计实现 java 熔断 微服务_断路器_06

降级的原理:

服务熔断计数统计实现 java 熔断 微服务_服务熔断计数统计实现 java_07

 

熔断和降级的本质就是 异常的步获和异常的处理;

项目中如何运用熔断降级:

熔断降级工具

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<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}断路器半开启(一会开,一会关)");
            }))

5、然后选择降级策略

//自定义异常处理(用缓存处理
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;
           }))

6、然后选择重试策略

.AddPolicyHandler(Policy<HttpResponseMessage>
              .Handle<Exception>()
              .RetryAsync(options.RetryCount)
            )

7、最后选择超时机制

.AddPolicyHandler(Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(options.TimeoutTime)));

 

我们在集合服务种添加polly 的nuget包

服务熔断计数统计实现 java 熔断 微服务_服务熔断计数统计实现 java_08

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<ConsulHttpClient>();
            #region polly配置(未封装)
            {
                //services.AddHttpClient("mrico")
                //// 1.1 降级(捕获异常,进行自定义处理)
                //.AddPolicyHandler(Policy<HttpResponseMessage>.Handle<Exception>().FallbackAsync(fallbackResponse, async b =>
                //{
                //    // 1、降级打印异常
                //    Console.WriteLine($"开始降级,异常消息:{b.Exception.Message}");
                //    // 2、降级后的数据
                //    //Console.WriteLine($"降级内容响应:{}");
                //    await Task.CompletedTask;
                //}))
                //// 1.2 熔断机制
                //.AddPolicyHandler(Policy<HttpResponseMessage>.Handle<Exception>().CircuitBreakerAsync(3, TimeSpan.FromSeconds(10), (ex, ts) =>
                //{
                //    Console.WriteLine($"断路器开启,异常消息:{ex.Exception.Message}");
                //    Console.WriteLine($"断路器开启时间:{ts.TotalSeconds}s");
                //}, () =>
                //{
                //    Console.WriteLine($"断路器重置");
                //}, () =>
                //{
                //    Console.WriteLine($"断路器半开启(一会开,一会关)");
                //}))
                //// 1.3 失败重试
                //.AddPolicyHandler(Policy<HttpResponseMessage>
                //  .Handle<Exception>()
                //  .RetryAsync(3)
                //)
                ////1.4、超时
                //.AddPolicyHandler(Policy.TimeoutAsync<HttpResponseMessage>(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<ConsulHttpClient>();

            /*// 2、注册consul服务发现
            services.AddConsulDiscovery();

            // 3、注册负载均衡
            services.AddSingleton<ILoadBalance, RandomLoadBalance>();*/

            // 4、注册team服务
            services.AddSingleton<ITeamServiceClient, HttpTeamServiceClient>();

            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();
            });
        }
    }

封装:

 

 

/// <summary>
    /// HttpClient熔断降级策略选项
    /// </summary>
   public class PollyHttpClientOptions
   {
        /// <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; }
    }

   /// <summary>
   /// 微服务中HttpClient熔断,降级策略扩展
   /// </summary>
   public static class 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 AddPollyHttpClient(this IServiceCollection services, string name,Action<PollyHttpClientOptions> action)
        {
            // 1、创建选项配置类
            PollyHttpClientOptions options = new PollyHttpClientOptions();
            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;
        }


    }