第四节: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 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。