三分钟学会.NET微服务之Polly

 

熔断降级是一个很是重要的概念,咱们先说一下什么是熔断降级,我们都知道服务发现,一个有问题的服务器没来得急注销过一会就崩溃掉了,那么咱们的请求就有可能访问一个已经崩溃的服务器,那么就会请求失败,由于已经game over了。那么这个问题怎么解决呢,你必定要认可,这个问题是没法避免的。没有什么方法说,我拿到的服务器都没有问题,这事是不可能的,因此你要认可你会有机会拿到有问题的服务器。那么熔断降级就是来解决这种问题的。git

 一.什么是熔断

熔断就像是“保险丝”,当出现梦中情况时,切断服务,从而防止应用程序不断地尝试形成雪崩,这和咱们农村的保险丝很像,天气热了防止火灾,那保险丝会自动断开,防止更大的损失。github

降级的目的是当某个服务提供者发生故障的时候,向调用方返回一个错误响应替代响应。redis

好比咱们要作一个双11活动的系统,那么好比一个抽奖的模块崩溃,这个时候呢广大客户端疯狂F5,就会致使整个集群雪崩,这个时候咱们就应该中断。数据库

还有一栗子,好比说电信和联通,它们在稳定,有也不稳定的时候,那么若是咱们用它们的接口,若是电信崩了,咱们就是用联通,这种操做的行为就叫作熔断降级。缓存

其使用场景呢,例如,咱们要展现商品信息,咱们先从数据库读取,读取失败了,咱们就经过cache/redis,若是再失败,咱们经过固定的Javascript object 来绑定,若是再失败那就返回一个错误的信息。这就是完美的下降了错误。服务器

这种错误的几率就犹如0.01*way³  就是1000次才会出现的几率。那若是是不熔断降级 就是100.以上一些栗子,好好读读便可。网络

二.Polly介绍

.Net Core 中有一个被.Net基金会承认的k库,能够用来进行熔断降级,主要功能:1.重试(retry);2.断路器(circuit-breaker);3.超时检测(timeout);4.缓存(cache);5.降级(fallback)app

 官方:https://github.com/app-vnext/polly  nuget: install-package Polly-Version 6.0.1框架

三.使用

建立项目与安装库,为了稳定仍是选择6.0.1吧。异步

使用Policy的静态方法建立ISyncPolicy实现类对象,建立方法j既有同步方法也有异步方法,根据本身的需求来选择,下面先演示同步方法,异步的方法也相似。

static void Main(string[] args)
        {
            //handle 当发生argumentException的异常
            Policy policy = Policy.Handle<ArgumentException>() .Fallback(() => { //就干什么事情 Console.WriteLine("出错了"); });
       //有可能异常的时候 policy.Execute(() => { Console.WriteLine("开始执行"); throw new ArgumentException(); Console.WriteLine("执行结束"); }); }

咱们运行一下,是以下结果。

但若是书咱们故意写一个抛出异常,咱们稍微修改一下代码。

policy.Execute(() =>
            {
                Console.WriteLine("开始执行"); throw new ArgumentException(); Console.WriteLine("执行结束"); });

上面呢,我么捕捉的是ArgumentException异常,那么咱们若是是报的其余的错误应该会怎样呢?

policy.Execute(() =>
            {
                Console.WriteLine("开始执行"); throw new Exception(); Console.WriteLine("执行结束"); });

 FallBack中有不少不一样的重载,咱们能够根据重载获取不一样的报错信息,如下是全部的方法。

咱们能够简单的去获取一个对象,代码以下:

 Policy policy = Policy.Handle<ArgumentException>()
                .Fallback(() => { //就干什么事情 Console.WriteLine("出错了"); },ex=> { Console.WriteLine(ex.Message); }); policy.Execute(() => { Console.WriteLine("开始执行"); throw new ArgumentException(); Console.WriteLine("执行结束"); });

由于我们的业务逻辑啊有多是带返回值的,也有多是不带返回值的。那若是你的业务逻辑是带返回值的,你就得用一个Policy带参的泛型来建立,那么这个Policy也是泛型的,在FallBack中也要 提一个替代值,由于毕竟是降级嘛,确定要有一个值来进行替代。

Policy<string> policy = Policy<string>.Handle<Exception>()
                .Fallback(() => { return "降级后的值"; }); string value = policy.Execute(() => { return "正常值"; });

四.重试处理

polly提供了重试处理机制,那么这个RetryForever()的场景不可能会出现,我也不知道它是处于什么个操做。我以为这违背了熔断降级,这不可能让它重试的,那么如下就是用法,可是这根本用不着~

仍是推荐使用Retry吧。Retry中能够写个int值进去,就是重试的次数,这个仍是不错的!

Policy policy = Policy.Handle<Exception>().RetryForever();
            policy.Execute(() => { Console.WriteLine("play task!!"); if (DateTime.Now.Second % 10 != 0) { throw new Exception(); } Console.WriteLine("完成任务!"); });

不过仍是有比较正常点的方法,例如WaitAndRetry这个方法,等等再重试。这个很不错!这个方法里的重载很是之多。

Policy policy = Policy.Handle<Exception>().WaitAndRetry(100, i => TimeSpan.FromMinutes(100));
            policy.Execute(() => { Console.WriteLine("play task!!"); if (DateTime.Now.Second % 10 != 0) { throw new Exception(); } Console.WriteLine("完成任务!"); });

 五.短路保护Circuit Breaker

短路保护是什么意思呢,这个单词翻译过来就叫作线路切断器,出现N次连续错误,则把“熔断器”(保险丝)熔断,等待一段时间,等待这段时间内若是再Execute则直接抛出BrokenCircuitException异常,根本不会再去尝试调用业务代码。等待时间过去以后,再执行Execute的时候若是又错了(一次就够了),那么继续熔断一段时间,不然就恢复正常。这样就避免一个服务已经不可用了,仍是使劲的请求给系统形成更大压力。

这样就避免了一个服务不可用了还在使劲的请求。

 Policy policy = Policy
            .Handle<Exception>() .CircuitBreaker(3, TimeSpan.FromSeconds(5));//连续出错3次以后熔断5秒(不会再 while (true) { Console.WriteLine("开始Execute"); try { policy.Execute(() => { Console.WriteLine("开始任务"); throw new Exception("出错"); Console.WriteLine("完成任务"); }); } catch (Exception ex) { Console.WriteLine("execute出错" + ex); } Thread.Sleep(500); }

 这就像刚才咱们说的,我设置了连续3次熔断,那么若是连续3次报错,那么直接再也不执行之后的内容,这无疑是很是不错的机制。保证了服务器的性能丢失和不起眼的问题。

 六.策略封装与超时处理

策略封装使用的方法是Policy提供的Wrap方法,英译叫作包裹,那么从单词的意思就知道,能够经过策略包裹策略来进行封装,即里面的不行,就走外面的。

Policy policyRetry = Policy.Handle<Exception>()
                .Retry(3); Policy policyFallback = Policy.Handle<Exception>() .Fallback(() => { Console.WriteLine("降级"); }); Policy policy = policyFallback.Wrap(policyRetry); policy.Execute(() => { Console.WriteLine("play task!!"); if (DateTime.Now.Second % 10 != 0) { throw new Exception(); } Console.WriteLine("完成任务!"); });

注意这个wrap的包裹顺序的,外在后,内在前。再经过一个超时处理就能够对消耗时间够长的请求进行GG了。

那么你就能够经过超时处理来对咱们文章开头的诉说进行一个很是生动形象的经过代码来宣誓。下面说明超时异常的说明

Policy policytimeout = Policy.Timeout(3, TimeoutStrategy.Pessimistic);
            Policy policyFallBack = Policy.Handle<TimeoutRejectedException>() .Fallback(() => { Console.WriteLine("熔断降级"); }); Policy policy = policyFallBack.Wrap(policytimeout); policy.Execute(() => { Console.WriteLine("完成任务"); Thread.Sleep(5000); Console.WriteLine("完成任务"); }); Console.ReadKey();

这玩腻的用途不过就是:请求网络接口,避免接口长期没有响应形成系统卡死。

 七.Polly的异步

     Test1().Wait(); //调用

        static async Task Test1() { Policy<byte[]> policy = Policy<byte[]> .Handle<Exception>() .FallbackAsync(async c => { Console.WriteLine("执行出错"); return new byte[0]; }, async r => { Console.WriteLine(r.Exception); }); policy = policy.WrapAsync(Policy.TimeoutAsync(20, TimeoutStrategy.Pessimistic, async (context, timespan, task) => { Console.WriteLine("timeout"); })); var bytes = await policy.ExecuteAsync(async () => { Console.WriteLine("开始任务"); HttpClient httpClient = new HttpClient(); var result = await httpClient.GetByteArrayAsync("https://www.cnblogs.com/images/logo_small.gif"); Console.WriteLine("完成任务"); return result; }); Console.WriteLine("bytes长度" + bytes.Length); }

使用Polly的异步,那么全部的方法都必须是异步,除了Handle方法,由于handle就不须要异步,也没有返回值。经过异步呢,全部的重载方法都构造了一遍,仍是能够继续用的。那么这段代码的意思是,经过异步的方式若是我经过httpclient获取某站点的图片的base值,若是在此期间我定义了一个policy,抓住一个异常,若是说两秒以内尚未反应我就超时。直接终止。测试的时候 你能够把值 改变下。

八.最后

相信你跟着我写到如今,已经感到这代码已经很是恶心了,代码中有很是多冗余的代码,近期会使用AspectCore这个AOP框架,听别人说这个库不错,这和Spring cloud的Hystrix差很少。就这样了,再见,喜欢点个推荐!

相关文章
相关标签/搜索