第四节:Polly基于控制台和Web端用法(熔断、降级、重试、超时处理等)

一. 简介

1. Polly是什么?

  Polly是 .Net Core 中有一个被.Net 基金会认可的库 ,可以用来简化熔断降级的处理。主要功能:失败处理-即降级(FallBack)、断路器-即熔断(CircuitBreaker)、重试(Retry)、超时检测(Timeout)、缓存(Cache)。java中的同类框架是著名的Hystrix。

2. 相关地址

 (1). 官网:http://www.thepollyproject.org/

 (2). GitHub:https://github.com/App-vNext/Polly

 (3). 两个程序集:

   官方的:【Polly  7.2.1】

   微软封装的:【Microsoft.Extensions.Http.Polly  3.1.5】

3. 如何理解熔断和降级

 调用端:指发送请求的端. 服务(Server)端:指提供Api接口的端。

 首先我们要明确的是熔断和降级都是作用在调用端上的,与Server端没关系。

 (1).熔断:是指当Server端出现宕机或超时情况,调用端所采用的一种策略应对机制,从而防止调用端不断地长时间执行可能会失败的操作,从而造成系统的“雪崩”, 或者大量的超时等待导致系统卡死等情况,很多地方也将其称为“过载保护”。

 PS:在Polly中熔断指 CircuitBreaker,即连续n次失败,就熔断一段时间,在这段时间内,不发送请求,走的是polly抛出的异常(报错:The circuit is now open and is not allowing calls.)。

 (2).降级:是指当Server端发生故障,调用端这里返回一个替代方案或者错误响应。比如:短信服务,假设最佳的是调用联通接口,但联通调用失败,我们退而求其次,降级调用移动的,移动的也失败,那么我们就返回失败响应了.

 PS:在Polly中降级指FallBack,走fallback中的业务,原策略业务 抛异常处 后面的代码不再执行了。

  

二. 基于控制台用法

前提:通过Nuget安装 【polly 7.2.1】

1.降级(Fallback)

{
                Policy policy = Policy.Handle<ArgumentException>()  //故障1
                                  .Or<ArgumentOutOfRangeException>()  //故障2
                                  .Or<IndexOutOfRangeException>()     //故障3
                                  .Fallback(() =>
                                  {
                                      //降级执行的动作
                                      Console.WriteLine("我是降级后的执行的操作");
                                  });

                policy.Execute(() =>
                {
                    //执行业务代码
                    Console.WriteLine("开始任务");
                    throw new ArgumentException("类型转换失败");
                    Console.WriteLine("结束任务");
                });
 }

运行结果:

2.降级-获取异常

            {
                Policy policy = Policy.Handle<ArgumentException>()  //故障1
                                       .Or<ArgumentOutOfRangeException>()  //故障2
                                       .Or<IndexOutOfRangeException>()     //故障3
                                       .Fallback(() =>
                                       {
                                           //降级执行的动作
                                           Console.WriteLine("我是降级后的执行的操作");
                                       }, ex =>
                                       {
                                           Console.WriteLine($"业务报错信息为:{ex.Message}");
                                       });

                policy.Execute(() =>
                {
                    //执行业务代码
                    Console.WriteLine("开始任务");
                    throw new ArgumentException("类型转换失败");
                    Console.WriteLine("结束任务");
                });
            }

运行结果:

3.降级-获取返回值

            {
                Policy<string> policy = Policy<string>.Handle<ArgumentException>()  //故障
                                  .Fallback(() =>
                                  {
                                      //降级执行的动作
                                      Console.WriteLine("我是降级后的执行的操作");
                                      return "我是降级业务中的返回值";
                                  });
                string value = policy.Execute(() =>
                  {
                      //执行业务代码
                      Console.WriteLine("开始任务");
                      throw new ArgumentException("类型转换失败");
                      Console.WriteLine("结束任务");
                      return "我是正常业务中的返回值";
                  });
                Console.WriteLine($"最终结果为:{value}");
            }

运行结果:

 

4.熔断机制

            //下面设置的是连续出错3次之后熔断10秒,意思是:连续出错3次后,熔断10s,在这10s内,再次访问,不再执行Execute中的代码,直接报错,
            //10s熔断时间过后,继续访问,如果还是出错(出一次即可),直接熔断10s, 再次重复这个过程
            {
                Policy policy = Policy
                 .Handle<Exception>()
                 .CircuitBreaker(3, TimeSpan.FromSeconds(10));    //连续出错3次之后熔断10秒(不会再去尝试执行业务代码)。 

                while (true)
                {
                    Console.WriteLine("开始Execute");
                    try
                    {
                        policy.Execute(() =>
                        {
                            Console.WriteLine("-------------------------------------开始任务---------------------------------------");
                            throw new Exception();
                            Console.WriteLine("完成任务");
                        });
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("execute出错" + ex.Message);
                    }
                    Thread.Sleep(2000);
                }
            }

运行结果:

 

5.重试机制

 指业务执行出错后,重新执行n次(总共执行了n+1次),这期间如果成功了,则后面不再执行,如果不成功,重试n次后,会把异常抛出来. 或者一直重复,直到成功。

 (1).Retry:出错后重新执行n次,期间成功则停止后续重试; 期间不成功,最后可以捕获异常.

 (2).RetryForever:出错后一直重试,直到成功才停止.

 (3).WaitAndRetry:出错后重新执行n次,每次间隔m秒.

 {
                try
                {
                    Policy policy = Policy
                    .Handle<Exception>()
                    .Retry(3); //出错后,连续执行3次
                    //.RetryForever();//出错后,连续执行,直到成功为止
                    //.WaitAndRetry(5, i => TimeSpan.FromSeconds(2));  //重试5次,每次间隔2s
                    int g = 0;
                    policy.Execute(() =>
                    {
                        Console.WriteLine($"开始任务,g={g}");
                        if (g < 10)
                        {
                            g++;
                            throw new Exception("业务出错了");
                        }

                        Console.WriteLine("完成任务");
                    });
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"捕获异常:{ex.Message}");
                }
}

运行结果

6.组合机制

 使用Wrap包裹,eg:policy6=Policy.Wrap(policy1, policy2)

 注意:Wrap是有包裹顺序的,内层的故障如果没有被处理则会抛出到外层.

(1).超时3秒降级:超时相关的 Policy.Timeout(3, TimeoutStrategy.Pessimistic);

 {
                //1.1 超时3秒
                Policy policytimeout = Policy.Timeout(3, TimeoutStrategy.Pessimistic);
                //1.2 降级
                Policy policyFallBack = Policy.Handle<TimeoutRejectedException>()
                   .Fallback(() =>
                   {
                       //降级执行的动作
                       Console.WriteLine("我是降级后的执行的操作");
                   }, ex =>
                   {
                       //捕获业务中的出错信息
                       Console.WriteLine(ex.Message);
                   });
                //1.3 将超时和降级操作进行组合
                Policy policy = policyFallBack.Wrap(policytimeout);
                //1.4 执行业务代码
                policy.Execute(() =>
                {
                    Console.WriteLine("开始任务");
                    Thread.Sleep(5000);
                    Console.WriteLine("完成任务");
                });
}

运行结果:

(2).重试+降级:重试3次,期间成功,则继续执行后面业务;期间失败,则走外层的降级操作

            {
                //2.1 遇到异常重试3次
                Policy policyRetry = Policy.Handle<Exception>().Retry(3);
                //2.2 降级操作
                Policy policyFallback = Policy.Handle<Exception>()
                                              .Fallback(() =>
                                              {
                                                  //降级执行的动作
                                                  Console.WriteLine("我是降级后的执行的操作");
                                              }, ex =>
                                              {
                                                  //捕获业务中的出错信息
                                                  Console.WriteLine(ex.Message);
                                              });
                //Wrap:包裹。policyRetry在里面,policyFallback在外面,如果里面出现了故障,则把故障抛出来给外面
                //2.3 进行包裹(出现错误,先重试3次,期间成功,则继续执行后面业务;期间失败,则走外层的降级操作)
                Policy policy = policyFallback.Wrap(policyRetry);
                int g = 0;
                //2.4 执行业务代码
                policy.Execute(() =>
                {
                    Console.WriteLine($"开始任务,g={g}");
                    if (g < 10)
                    {
                        g++;
                        throw new Exception("业务出错了");
                    }

                    Console.WriteLine("完成任务");
                });
            }

运行结果:

(3).熔断+降级:Execute执行业务代码无须再用Try-catch包裹,否则不抛异常,则无法降级,我们这里演示的是降级,并在降级中拿到业务代码的异常信息

            {
                //3.1 熔断
                Policy policyCBreaker = Policy.Handle<Exception>()
                                        .CircuitBreaker(3, TimeSpan.FromSeconds(10));    //连续出错3次之后熔断10秒(不会再去尝试执行业务代码)。 
                //3.2 降级
                Policy policyFallback = Policy.Handle<Exception>()
                                       .Fallback(() =>
                                       {
                                           //降级执行的动作
                                           Console.WriteLine("我是降级后的执行的操作");
                                       }, ex =>
                                       {
                                           //这里是捕获业务代码中的错误,业务代码中就不要再写try-catch,否则不抛异常,则无法降级
                                           Console.WriteLine($"业务报错信息为:{ex.Message}");
                                       });
                //3.4 包裹
                Policy policy = policyFallback.Wrap(policyCBreaker);

                //3.4 执行业务
                while (true)
                {
                    Console.WriteLine("开始Execute");
                    //try
                    //{
                    policy.Execute(() =>
                    {
                        Console.WriteLine("-------------------------------------开始任务---------------------------------------");
                        throw new Exception();
                        Console.WriteLine("完成任务");
                    });
                    //}
                    // 不要再写try-catch,否则不抛异常,则无法降级
                    //catch (Exception ex)
                    //{
                    //    Console.WriteLine("execute出错" + ex.Message);
                    //}
                    Thread.Sleep(2000);
                }
            }

运行结果:

 

 

 

三. 基于Web端用法

 

 后续补充。。

 

 

 

 

 

 

 

 

!

  • 作       者 : Yaopengfei(姚鹏飞)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 声     明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
  • 声     明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
 

 

posted @ 2020-05-25 21:44  Yaopengfei  阅读(1427)  评论(5编辑  收藏  举报