弹性和瞬态故障处理库Polly介绍

前言

本节我们来介绍一款强大的库Polly,Polly是一种.NET弹性和瞬态故障处理库,允许我们以非常顺畅和线程安全的方式来执诸如行重试,断路,超时,故障恢复等策略。 Polly针对对.NET 4.0,.NET 4.5和.NET Standard 1.1以及.NET Core实现,该项目作者现已成为.NET基金会一员,项目一直在不停迭代和更新,项目地址【https://github.com/App-vNext/Polly】,你值得拥有。接下来我们以.NET Framework  4.5来演示它的强大功能。

Introduce Polly

我们在下载Polly包,最新版本为5.3.1,如下:

该库实现了七种恢复策略,下面我一一为您来介绍。

重试策略(Retry)

重试策略针对的前置条件是短暂的故障延迟且在短暂的延迟之后能够自我纠正。允许我们做的是能够自动配置重试机制。

断路器(Circuit-breaker)

断路器策略针对的前置条件是当系统严重挣扎时,快速失败比让用户/呼叫者等待更好。保护故障系统免受过载,可以帮助它恢复。

超时(Timeout)

超时策略针对的前置条件是超过一定的等待时间,想要得到成功的结果是不可能的,保证调用者不必等待超时。

隔板隔离(Bulkhead Isolation)

隔板隔离针对的前置条件是当进程出现故障时,备份的多个失败的呼叫可以轻松地在主机中对资源(例如线程/ CPU)进行漫游。下游系统故障也可能导致上游“备份”失败的呼叫。这两个风险都是一个错误的过程,导致更广泛的系统。

缓存(Cache)

缓存策略针对的前置条件是数据不会很频繁的进行更新,为了避免系统过载,首次加载数据时将响应数据进行缓存,如果缓存中存在则直接从缓存中读取。

反馈(Fallback)

操作仍然会失败,也就是说当发生这样的事情时我们打算做什么。也就是说定义失败返回操作。

策略包装(PolicyWrap)

策略包装针对的前置条件是不同的故障需要不同的策略,也就意味着弹性灵活使用组合。

几种策略使用

一旦从事IT就得警惕异常并友好拥抱异常而非不闻不问,这个时候我们利用try{}catch{}来处理。

            try{                var a = 0;                var b = 1 / a;}            catch (DivideByZeroException ex){                throw ex;}


若我们想重试三次,此时我们只能进行循环三次操作。我们只能简单进行处理,自从有了Polly,什么重试机制,超时都不在话下,下面我们来简短介绍各种策略。Polly默认处理策略需要指定抛出的具体异常或者执行抛出异常返回的结果。处理单个类型异常如下:

Policy.Handle<DivideByZeroException>()

上述异常指尝试除以0,下面我们演示下具体使用,我们尝试除以0并用Polly指定该异常并重试三次。

        static int Compute(){            var a = 0;        
                    
return 1 / a;}


            try{                var retryTwoTimesPolicy =Policy.Handle<DivideByZeroException>().Retry(3, (ex, count) =>{Console.WriteLine("执行失败! 重试次数 {0}", count);Console.WriteLine("异常来自 {0}", ex.GetType().Name);});retryTwoTimesPolicy.Execute(() =>{Compute();});}            catch (DivideByZeroException e){Console.WriteLine($"Excuted Failed,Message: ({e.Message})");}


如果我们想指定处理多个异常类型通过OR即可。

Policy.Handle<DivideByZeroException>().Or<ArgumentException>()

当然还有更加强大的功能,比如在微信支付时,微信回调我们的应用程序时,此时若失败,想必微信那边也会做重试机制,例如隔一段时间重试调用一次,重复调用几次后仍失败则不再回调。我们利用Polly则可以演示等待重试机制。

        /// <summary>/// 抛出异常        /// </summary>static void ZeroExcepcion(){            throw new DivideByZeroException();}


        /// <summary>/// 异常信息        /// </summary>/// <param name="e"></param>/// <param name="tiempo"></param>/// <param name="intento"></param>/// <param name="contexto"></param>static void ReportaError(Exception e, TimeSpan tiempo, int intento, Context contexto){Console.WriteLine($"异常: {intento:00} (调用秒数: {tiempo.Seconds} 秒)\t执行时间: {DateTime.Now}");}


            try{     var politicaWaitAndRetry = Policy.Handle<DivideByZeroException>().WaitAndRetry(new[]{TimeSpan.FromSeconds(1),TimeSpan.FromSeconds(3),TimeSpan.FromSeconds(5),TimeSpan.FromSeconds(7)}, ReportaError);politicaWaitAndRetry.Execute(() =>{ZeroExcepcion();});}            catch (Exception e){Console.WriteLine($"Executed Failed,Message:({e.Message})");}

我们讲完默认策略和重试策略,再来看看反馈策略,翻译的更通俗一点则是执行失败后返回的结果,此时要为Polly指定返回类型,然后指定异常,最后调用Fallback方法。

        static string ThrowException(){            throw new Exception();}


           var fallBackPolicy =Policy<string>.Handle<Exception>().Fallback("执行失败,返回Fallback");            var fallBack = fallBackPolicy.Execute(() =>{                return ThrowException();});Console.WriteLine(fallBack);


包裹策略说到底就是混合多种策略,并执行。

      var fallBackPolicy =Policy<string>.Handle<Exception>().Fallback("执行失败,返回Fallback");            var fallBack = fallBackPolicy.Execute(() =>{                return ThrowException();});Console.WriteLine(fallBack);      
      
var politicaWaitAndRetry = Policy<string>.Handle<Exception>().Retry(3, (ex, count) =>{Console.WriteLine("执行失败! 重试次数 {0}", count);Console.WriteLine("异常来自 {0}", ex.GetType().Name);});        
   
var mixedPolicy = Policy.Wrap(fallBackPolicy, politicaWaitAndRetry);        
   
var mixedResult = mixedPolicy.Execute(ThrowException);Console.WriteLine($"执行结果: {mixedResult}");

至此关于Polly的基本介绍就已结束,该库还是非常强大,更多特性请参考上述github例子,接下来我们来看看两种具体场景。

ASP.NET Web APi使用Polly重试机制

在Polly v4.30中以上可以利用HandleResult指定返回结果,如下:

Policy.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.NotFound)

基于此我们完全可以利用执行Web APi中的响应策略,如下:

 public readonly RetryPolicy<HttpResponseMessage> _httpRequestPolicy;

拿到响应中状态码,若为500则重试三次。

 _httpRequestPolicy = Policy.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.InternalServerError).WaitAndRetryAsync(3,retryAttempt => TimeSpan.FromSeconds(retryAttempt));

上述获取请求响应策略在构造函数中获取。

    public class PollyController : ApiController{       

      
public readonly RetryPolicy<HttpResponseMessage> _httpRequestPolicy;      
       
public PollyController(){_httpRequestPolicy = Policy.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.InternalServerError).WaitAndRetryAsync(3,retryAttempt => TimeSpan.FromSeconds(retryAttempt));}}

此时调用接口时执行策略的Execute或者ExecuteAsync方法即可。

        public async Task<IHttpActionResult> Get(){          
  
var httpClient = new HttpClient();        
    
string requestEndpoint = "http://localhost:4096";HttpResponseMessage httpResponse = await _httpRequestPolicy.ExecuteAsync(() => httpClient.GetAsync(requestEndpoint));IEnumerable<string> numbers = await httpResponse.Content.ReadAsAsync<IEnumerable<string>>();            return Ok(numbers);}

你以为除了在Web APi中使用,在其他框架中也可以使用,例如EntityFramework 6.x中,在EntityFramework 6+上出现了执行策略,也就是执行重试机制,这个时候我们依然可以借助Polly轮子来实现。

EntityFramework 6.x使用Polly重试机制

在EntityFramework 6.x中有如下执行策略接口,看起来是不是和Polly中的Execute方法是不是很类似。

//

    // 摘要:

    //     A strategy that is used to execute a command or query against the database, possibly

    //     with logic to retry when a failure occurs.

    public interface IDbExecutionStrategy

    {

        //

        // 摘要:

        //     Indicates whether this System.Data.Entity.Infrastructure.IDbExecutionStrategy

        //     might retry the execution after a failure.

        bool RetriesOnFailure { get; }


        //

        // 摘要:

        //     Executes the specified operation.

        //

        // 参数:

        //   operation:

        //     A delegate representing an executable operation that doesn't return any results.

        void Execute(Action operation);

        //

        // 摘要:

        //     Executes the specified operation and returns the result.

        //

        // 参数:

        //   operation:

        //     A delegate representing an executable operation that returns the result of type

        //     TResult.

        //

        // 类型参数:

        //   TResult:

        //     The return type of operation.

        //

        // 返回结果:

        //     The result from the operation.

        TResult Execute<TResult>(Func<TResult> operation);

        //

        // 摘要:

        //     Executes the specified asynchronous operation.

        //

        // 参数:

        //   operation:

        //     A function that returns a started task.

        //

        //   cancellationToken:

        //     A cancellation token used to cancel the retry operation, but not operations that

        //     are already in flight or that already completed successfully.

        //

        // 返回结果:

        //     A task that will run to completion if the original task completes successfully

        //     (either the first time or after retrying transient failures). If the task fails

        //     with a non-transient error or the retry limit is reached, the returned task will

        //     become faulted and the exception must be observed.

        Task ExecuteAsync(Func<Task> operation, CancellationToken cancellationToken);

        //

        // 摘要:

        //     Executes the specified asynchronous operation and returns the result.

        //

        // 参数:

        //   operation:

        //     A function that returns a started task of type TResult.

        //

        //   cancellationToken:

        //     A cancellation token used to cancel the retry operation, but not operations that

        //     are already in flight or that already completed successfully.

        //

        // 类型参数:

        //   TResult:

        //     The result type of the System.Threading.Tasks.Task`1 returned by operation.

        //

        // 返回结果:

        //     A task that will run to completion if the original task completes successfully

        //     (either the first time or after retrying transient failures). If the task fails

        //     with a non-transient error or the retry limit is reached, the returned task will

        //     become faulted and the exception must be observed.

        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]

        Task<TResult> ExecuteAsync<TResult>(Func<Task<TResult>> operation, CancellationToken cancellationToken);

    }

EntityFramework 6.x中的执行策略说到底就是数据库连接问题即弹性连接,若考虑到数据库过渡负载问题,此时应用程序和数据库之间存在网络问题的话。可能数据库连接在几秒内才返回,此时也没有什么很大的问题,我们完全可以再尝试一次,此时或许过了连接频繁期,保证连接立马恢复。如果数据库连接一会恢复不了呢?或许是五分钟,又或者是半个小时。如果我们只是一味盲目的进行重试,这显然不可取。如果我们的应用程序连接超时时间超过了20秒,若我们选择继续连接到数据库,我们将很快用完我们应用程序池中的工作线程。一直等待数据库的响应。此时网站将完全无响应,同时会给用户页面无响应的友好提醒。这是Polly库中描述断路器的很好例子,换句话说如果我们捕获了m个数量的SqlExceptions,假设数据库有其他问题存在,导致我们不能在n秒内再尝试连接数据库。此时在数据库连接上存在一个问题,那就是阻塞了我们的应用程序工作线程被挂起,我们试图连接数据库,我们假设不可用的话,但是我们要打破这种不可用,那就用Polly吧。

 

我们看到上述EntityFramework 6.x实现了IDbExecutionStrategy接口,但没有实现如Polly中的断路器模式,EntityFramework 6.x中的执行策略只是重试机制而已。 比如SqlAzureExecutionStrategy将在指定的时间段内重试指定的次数,直到一段时间段过去,重试指数过后,接着就是失败。 同时所有后续调用将执行相同操作,重试并失败。 这是调用数据库时最好的策略吗? 不敢肯定,或许Polly中的断路器模式值得我们借鉴。我们自己来实现上述执行策略接口。

    public class CirtuitBreakerExecutionStrategy : IDbExecutionStrategy{      
     
private Policy _policy;    
     
public CirtuitBreakerExecutionStrategy(Policy policy){_policy = policy;}    

      
public void Execute(Action operation){_policy.Execute(() =>{operation.Invoke();});}      
public TResult Execute<TResult>(Func<TResult> operation){            return _policy.Execute(() =>{                return operation.Invoke();});}      

 
public async Task ExecuteAsync(Func<Task> operation, CancellationToken cancellationToken){          
 
await _policy.ExecuteAsync(() =>{      
return operation.Invoke();});}        

public async Task<TResult> ExecuteAsync<TResult>(Func<Task<TResult>> operation, CancellationToken cancellationToken){          
 
return await _policy.ExecuteAsync(() =>{            
return operation.Invoke();});}      
  
public bool RetriesOnFailure { get { return true; } }}


接下来在基于代码配置文件中设置我们上述自定义实现的断路器模式。

    public class EFConfiguration : DbConfiguration{     
       
public Policy _policy;    
   
       
public EFConfiguration(){_policy = Policy.Handle<Exception>().CircuitBreaker(3, TimeSpan.FromSeconds(60));SetExecutionStrategy("System.Data.SqlClient", () => new CirtuitBreakerExecutionStrategy(_policy));}}

上述自定义实现执行策略不保证一定有用或许也是一种解决方案呢。

总结

本节我们介绍了强大的Polly库和其对应使用的两种实际场景,有此轮子我们何不用起,将其进行封装可以用于一切重试、缓存、异常处理。 

相关文章: 

  • 云计算设计模式(一)缓存预留模式

  • 使用熔断器设计模式保护软件

  • 云计算设计模式(二)——断路器模式

  • API网关Ocelot 使用Polly 处理部分失败问题

原文地址:http://www.cnblogs.com/CreateMyself/p/7589397.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/323439.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一分钟理解Java包装类型

转载自 一分钟理解Java包装类型 Java 一直标榜自己是一个纯粹的面向对象语言&#xff0c;自作聪明的为所有的值类型都提供相应的引用类型&#xff08;不明白这两个概念&#xff0c;看之前的《一分钟理解传值和传引用》&#xff09;比如&#xff1a;int 类型对应的有 Integer&…

SQL Server 2017 正式发布

SQL Server 2017 跨出了重要的一步&#xff0c;它力求通过将 SQL Server 的强大功能引入 Linux、基于 Linux 的 Docker 容器和 Windows&#xff0c;使用户可以在 SQL Server 平台上选择开发语言、数据类型、本地开发或云端开发&#xff0c;以及操作系统开发。微软拥抱开源的脚步…

关于链表的简单创建和遍历

这是网上的的源码&#xff1a; #include <stdio.h> #include <stdlib.h> #include <malloc.h>// 定义链表中的节点 typedef struct node {int member; // 节点中的成员struct node *pNext; // 指向下一个节点的指针 }Node,*…

可能是最全面的 Java G1学习笔记

转载自 可能是最全面的 Java G1学习笔记 引子 最近遇到很多朋友过来咨询G1调优的问题&#xff0c;我自己去年有专门学过一次G1&#xff0c;但是当时只是看了个皮毛&#xff0c;因此自己也有不少问题。总体来讲&#xff0c;对于G1我有几个疑惑&#xff0c;希望能够在这篇文章中…

微服务~Eureka实现的服务注册与发现及服务之间的调用

微服务里一个重要的概念就是服务注册与发现技术&#xff0c;当你有一个新的服务运行后&#xff0c;我们的服务中心可以感知你&#xff0c;然后把加添加到服务列表里&#xff0c;然后当你死掉后&#xff0c;会从服务中心把你移除&#xff0c;而你作为一个服务&#xff0c;对其它…

新高考增值评价系统业务简单介绍(超详细,图文并茂)

大家好&#xff0c;我是雄雄。 文章目录一&#xff1a;基本信息1&#xff1a;学校信息2&#xff1a;教师管理1&#xff1a;下载教师模板2&#xff1a;上传教师模板3&#xff1a;查看教师数据4&#xff1a;教师信息编辑5&#xff1a;新增教师6&#xff1a;导出教师数据3&#xf…

一步一步详解高斯日记

这是有一年的蓝桥杯的题目&#xff0c;感觉挺有趣的 意思就是高斯有个习惯&#xff0c;记日期的时候喜欢只用数字来记&#xff0c;比如如果你2001年一月一日出生的话&#xff0c;你活到2002年1 月一日&#xff0c;他就会写个366。大致意思就是你现在的时间减去个出生的时间1就是…

微服务配置中心实战:Spring + MyBatis + Druid + Nacos

转载自 微服务配置中心实战&#xff1a;Spring MyBatis Druid Nacos 很多基于 Spring MVC 框架的 Web 开发中&#xff0c;Spring MyBatis Druid 是一个黄金组合&#xff0c;在此基础上如果融入一个配置中心&#xff0c;会发生什么特别的变化呢&#xff1f; 本文将通过一…

揭晓新版《Windows Sysinternals实战指南》读书积赞活动

参与新版《Windows Sysinternals实战指南》&#xff0c;读书积赞活动的一下三位同学&#xff08;想法构成&#xff0c;我zzz&#xff0c;kergee&#xff09;&#xff0c;请加我微信geffzhang&#xff0c;把姓名&#xff0c;地址和手机号发给我&#xff0c;后续给你们寄书。.NET…

Spring Cloud 终于按捺不住推出了自己的服务网关 Gateway

转载自 Spring Cloud 终于按捺不住推出了自己的服务网关 Gateway Spring 官方最终还是按捺不住推出了自己的网关组件&#xff1a;Spring Cloud Gateway &#xff0c;相比之前我们使用的 Zuul&#xff08;1.x&#xff09; 它有哪些优势呢&#xff1f;Zuul&#xff08;1.x&…

ASP.NET Core中如何调整HTTP请求大小的几种方式

一、前言 一般的情况下&#xff0c;我们都无需调用HTTP请求的大小&#xff0c;只有在上传一些大文件&#xff0c;或者使用HTTP协议写入较大的值时&#xff08;如调用WebService&#xff09;才可能会调用HTTP最大请求值。 在ASP.NET Core 2.0中&#xff0c;它的两个宿主服务器Ke…

csdn颜色字体的改变

一直想改变一下csdn界面字体的颜色&#xff0c;奈何csdn上没有像Word那样直接改变字体颜色的版面&#xff0c;找半天没找到&#xff0c;后来才知道必须输入代码才能改变字体颜色&#xff0c;这个就很高级了啊 <font face"微软雅黑" color#FF8C00 size2> **一…

ASP.NET Core 2.0 使用支付宝PC网站支付

前言 最近在使用ASP.NET Core来进行开发&#xff0c;刚好有个接入支付宝支付的需求&#xff0c;百度了一下没找到相关的资料&#xff0c;看了官方的SDK以及Demo都还是.NET Framework的&#xff0c;所以就先根据官方SDK的源码&#xff0c;用.NET Standard 2.0 实现了支付宝服务端…

mysql实现查询分组查询最后一次的记录

大家好&#xff0c;我是雄雄。 前言 又好久没有写博客了&#xff0c;为什么呢&#xff1f;因为最近没怎么写代码…说起来也惭愧。 今天在项目上遇到了个需求&#xff0c;是这样的&#xff1a;我们数据库中有一表检测记录表&#xff0c;该表中存储的是所有居民每次的检测记录&…

常用公有云接入——华为

一、介绍 1、什么是弹性云服务器? 弹性云服务器是由CPU、内存、镜像、云硬盘组成的一种可随时获取、弹性可扩展的计算服务器&#xff0c;同时它结合虚拟私有云、虚拟防火墙、数据多副本保存等能力&#xff0c;为您打造一个高效、可靠、安全的计算环境&#xff0c;确保您的服…

jenkins~集群分发功能和职责处理

jenkins的多节点集群 在进行自动化部署时&#xff0c;你可以按着它们的项目类型去进行分别部署&#xff0c;这样即可以达到负载均衡&#xff0c;又可以达到一种职责的明确&#xff0c;比如像java的项目你可以使用linux服务来进行部署&#xff08;拉代码&#xff0c;还原&#x…

nginx中配置https的步骤

大家好&#xff0c;我是雄雄。 想必大家都有过配置https的需求吧&#xff0c;今天我就来整理一下&#xff0c;如何在nginx里面配置https 这里先忽略https申请&#xff0c;一般在你申请域名的那里直接弄就行&#xff0c;下面是nginx中的配置代码&#xff1a; server {listen …

爬取网页图片

前言 这几天又看了下python的视频&#xff0c;突然又对python感兴趣起来。以前只是学了下python的基础&#xff0c;感觉和其他语言没什么大的区别&#xff0c;再加上编程游戏的插件pygame一直没装上&#xff0c;遂放弃了。 最近心血来潮突然又想用python来搞游戏开发&#xff…

sql中索引不会被用到的几种情况

转载自 sql中索引不会被用到的几种情况 1、查询谓词没有使用索引的主要边界,换句话说就是select *&#xff0c;可能会导致不走索引。 比如&#xff0c;你查询的是SELECT * FROM T WHERE YXXX;假如你的T表上有一个包含Y值的组合索引&#xff0c;但是优化器会认为需要一行行的…

asp.net core合并压缩资源文件引发的学习之旅

0. 在asp.net core中使用BuildBundlerMinifier合并压缩资源文件 在asp.net mvc中可以使用Bundle来压缩合并css,js 不知道的见&#xff1a;http://www.cnblogs.com/morang/p/7207176.html 在asp.net core中则可以使用BuildBundlerMinifier来进行css&#xff0c;js的压缩合并 新建…