如何用ASPNETCore实现熔断和降

北京治疗白癜风去哪家 https://wapjbk.39.net/yiyuanfengcai/yyjs_bjzkbdfyy/

作者

朱钢

责编

屠敏

熔断、降级和AOP

1.什么是熔断?

熔断常常出现在股市中,是指当股指波幅达到规定的熔断点时,交易所为控制风险采取的暂停交易措施。同样,在程序中也引入了熔断,程序中的熔断和股市中的熔断具有类似的意思,当下游服务因访问压力过大而响应变慢或失败,或者下游服务出现异常时,上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。如果项目中不适用熔断将会影响到整个系统的使用,我们来看一个例子。

在一个系统中存在A、B、C这三个服务(子系统)。正常情况下A调用B,B再调用C,返回的数据会按照C、B、A的顺序来返回。这时当C因为某种原因导致数据处理量减少或者B发送了超出C处理能力的数据量,这时C就产生的阻塞。不仅大量的数据一直在等待C来处理,B还会继续发送数据到C。但是因为C的处理能力有限,B又无法得到响应,这时B也产生了阻塞,同样的A继续发送数据给B,一段时间后A无法得到响应A出现了阻塞。那么这个时候整个系统就都出现问题了,最后系统崩溃。这种链路故障被称为雪崩。

当我们引入了熔断机制这种情况就完全可以避免。在引入熔断之前,我们需要知道两个概念开启熔断和恢复熔断。

开启熔断在固定时间范围内接口的调用超时比率达到或超过一个阈值就会开启熔断。之后对该服务接口的调用将不再经过网络,而是自行本地的默认方法,这样就达到了服务降级的效果。恢复熔断熔断经过了设定的时间之后,服务将从熔断状态恢复位初始状态,之后再次接受调用方的远程调用。当调用服务超时比率再次达到或超过一个阈值就会重新开启熔断。好到现在未知我们已经了解了这两个概念,前面的例子只需要在每个调用初增加熔断机制即可,当出现超时比率到达所定义的阈值时,熔断机制将启动。经过一段时间后达到了重试的时间,服务的熔断状态消失,再次开始调用。2.什么是降级

降级是当某个服务出现故障启动熔断机制后,向调用方返回一个替代响应或者规范化的错误响应。例如我们的程序需要发送邮件,首先调用自建邮箱发送,当自建邮箱发送失败后调用网易邮箱发送邮件,如果网易邮箱发送失败,那么我们就调用QQ邮箱发送,如果QQ邮箱也发送失败,那么我们就返回发送失败响应。降级也可以看作服务的选择性放弃,例如在电商活动中为了应对大规模请求,都会将部分服务优先级降低或者暂停服务,等待峰值下降后再恢复被降级服务的优先级。

3.AOP

所谓的AOP就是面向切面编程,是指在运行时动态的将代码加入到指定的方法中或指定的位置中的编程思想。常见的AOP场景是日志记录,在面向对象的编程中类之间无法直接进行联系,因此无法将重复的日志代码封装起来。这时我们就可以利用AOP来解决,把多个类公用的代码抽取出来做为一个切片,在我们需要用到时再把它切入到指定的方法或位置中。我们一般把放入到指定方法或指定类中的代码称为切面,被切入的方法、类和位置被称为切入点。AOP和OOP相辅相成,OOP是从横向上规划处多个类,而AOP是从纵向上向对象中加入指定的代码,AOP和OOP的结合使得代码变得更具立体感。

实现ASP.NETCore熔断与降级

前面说了那么多,现在我们就来看一下ASP.NETCore是怎么实现熔断和降级的。在这里我们需要用到一个第三方库Polly。它是被.NET基金会认客的弹性和瞬态故障处理库,可以让我们以顺畅并且线程安全的方式来执行重试、断路(熔断)、故障恢复等策略。Polly包含7个功能:重试、断路(熔断)、降级、超时、隔离、缓存以及策略包集合Polly的核心是动作和故障,其中动作主要包含降级、熔断和重试等,策略则包含用来执行的代码。

下面我们来讲解一下Polly的这7个功能:

1.重试

重试比较好理解,当出现故障时需要重新执行部分代码,代码如下:

classProgram{staticvoidMain(string[]args){try{Policy.HandleHttpRequestException().Retry(5,((exception,count,context)={Console.WriteLine(第{count}次重试);})).Execute(GetUser);}catch(Exceptione){Console.WriteLine(异常抛出);}Console.Read();}staticvoidGetUser(){Console.WriteLine(开始);Thread.Sleep();thrownewHttpRequestException();}}

在上面的代码中我们定义了一个GetUser方法,这个方法用来模拟网络请求并在方法结尾制造了一个Http异常。在Main方法中我们设定了重试次数5次,并且规定了重试过程中要执行的业务逻辑,最后调用Execute方法指定针对哪段代码执行这个策略。我们运行代码可以发现当触发异常后,程序不断的重试调用指定的代码段,直到达到重试次数后不再重试并抛出异常。我们在使用重试策略需要注意的是,当达到重试次数后代码会抛出异常,因此我们必须在将充实策略代码包裹在try_catch代码段中。

2.降级

当无法避免的错误发生时,需要要有一个合理的返回来代替失败。例如当一个用户使用手机号加验证码的形式注册的时候是没有密码的,这时我们需要给它设置一个默认的密码。

Policy.HandleWhatever().FallbackUser(()=User.SetPassword())

3.断路

当遇到严重问题时,我们要做的是马上将失败信息反馈给调用方而不是让调用方一直等待。例如当我们的程序调第三方开发的API时,这时第三方API很长时间都没有响应,那么这时我们可以认为第三方API有很大可能出现了问题(例如服务器宕机、APIbug等)。如果这时我们的程序还在一直重试,那么不仅会加重系统的负担,而且还有可能造成程序其它部分受影响,甚至整个程序崩溃。因此当系统出错的次数超过指定阈值,就必须中断所有的请求并等待一定时间后再继续。同样我们来看一下代码:

Policy.HandleHttpRequestException().CircuitBreaker(10,TimeSpan.FromSeconds(5),(exception,ts)={Console.WriteLine(系统{exception.Message}在{ts.Seconds}秒后重试);},()={Console.WriteLine(重启!);}).Execute(GetUser);

上述代码段定义了断路策略,当程序出现Http异常10次时就暂停5秒钟后继续执行,并且这段代码还定义了断路时中断所执行的代码和重启时所需要执行的代码。

4.超时

当程序等待超过一定时间后我们就可以判断不可能会成功了。这种情况经常发生在网络请求中,例如正常情况下请求一次数据几乎是瞬间完成,如果在一次网络请求超过了N秒还没完成就说明本次请求出现异常,因此我们需要设置程序的超时时间N来避免程序长时间的等待。

Policy.Timeout(20,(context,timespan,task)={Console.WriteLine({context}{timespan}{task});}).Execute(GetUser);

上述代码中定义了当等待时间超过20秒后将触发回调函数。

5.隔离

当程序某处出现故障可能会促发多个失败的调用,这样就很容易耗尽宿主机资源。因此要将可控的操作限制在一个固定大小的资源池中,以隔离有潜在可能相互影响的操作。例如利用Polly策略设置最多允许5个线程并发执行,如果执行被拒绝则执行回调。

Policy.Bulkhead(12,context={Console.WriteLine(回调代码)});

6.缓存

在开发时我们会把频繁使用并且很少变化的资源缓存起来,来提高系统的性能。Polly提供了强大且易于上手的缓存策略的支持,使得我们不用再手动编写缓存策略。这里我不提供示例代码,是因为这一小部分需要根据不同项目和不同公司的框架来订。

7.策略集合

当一个操作有不同的故障,并且不同的故障处理需要不同的策略时这些不同的策略必须作为一个集合放在在一起才能应用在同一种操作上。这时我们可以这么来写策略集合:

Policy.Wrap(fallback,cache,retry,breaker,timeout,bulkhead);

总结

本文开头主要介绍了软缎和降级的相关概念,然后用讲解了Polly的其中策略,这些都可以作为掌握Polly的基础。因为Polly是一个强大而丰富的.NET第三方库,无法通过一篇文章具体而又详细的讲解出来,因此对于Polly和熔断以及降级有兴趣的同学可以上Polly官方文档中具体学习。

作者简介:朱钢,笔名喵叔,CSDN博客专家,.NET高级开发工程师,7年一线开发经验,参与过电子政务系统和AI客服系统的开发,以及互联网招聘网站的架构设计,目前就职于北京恒创融慧科技发展有限公司,从事企业级安全监控系统的开发。




转载请注明:http://www.shhjfk.com/jyqj/jyqj/14314.html