已被.NET基金会认可的弹性和瞬态故障处理库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)
断路器策略针对的前置条件是当系统繁忙时,快速响应失败总比让用户一直等待更好。保护系统故障免受过载,Polly可以帮其恢复。
超时(Timeout)
超时策略针对的前置条件是超过一定的等待时间,想要得到成功的结果是不可能的,保证调用者不必等待超时。
隔板隔离(Bulkhead Isolation)
隔板隔离针对的前置条件是当进程出现故障时,多个失败一直在主机中对资源(例如线程/ CPU)一直占用。下游系统故障也可能导致上游失败。这两个风险都将造成严重的后果。都说一粒老鼠子屎搅浑一锅粥,而Polly则将受管制的操作限制在固定的资源池中,免其他资源受其影响。
缓存(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库和其对应使用的两种实际场景,有此轮子我们何不用起,将其进行封装可以用于一切重试、缓存、异常等处理。
我的博客即将入驻“云栖社区”,诚邀技术同仁一同入驻。
已被.NET基金会认可的弹性和瞬态故障处理库Polly介绍相关推荐
- 弹性和瞬态故障处理库Polly介绍
前言 本节我们来介绍一款强大的库Polly,Polly是一种.NET弹性和瞬态故障处理库,允许我们以非常顺畅和线程安全的方式来执诸如行重试,断路,超时,故障恢复等策略. Polly针对对.NET 4. ...
- 弹性和瞬态故障处理库Polly之重试策略
弹性和瞬态故障处理库Polly 源码及参考见文章底部 Nuget中Polly库的引用: Install-Package Polly 以下策略调用的方法: 详细代码见 public static int ...
- c# 弹性和瞬态故障处理库Polly 学习
关于Polly Polly是一个基于.NET的弹性及瞬态故障处理库,允许开发人员以顺畅及线程安全的方式执行重试(Retry).断路(Circuit Breaker).超时(Timeout). 隔离(B ...
- c# 弹性和瞬态故障处理库Polly
关于polly polly文档中对自己介绍的原文是: Polly is a .NET resilience and transient-fault-handling library that allo ...
- 人人车李健:合伙人总数突破千人 已得到市场初步认可
新浪科技讯 3月1日晚间消息,人人车创始人兼CEO李健发布全员内部信,宣布人人车"新平台,新零售"战略首战告捷,十天时间,人人车合伙人总数突破千人. 李健表示,阶段性的突破体现了人 ...
- 国产操作系统如何?中兴这操作系统已获国家安全认可
当全球科技竞争日益加剧,操作系统是我国的软肋,目前,我国移动终端系统市场被谷歌安卓统治,桌面终端系统市场微软的Windows独大.这种情况下,国内企业一直在努力改变系统受制于人的现状,华为有鸿蒙系统, ...
- 已帮助上千人成功入职2022软件测试面试自我介绍,软件测试常见面试题
目录 一.自我介绍 二.项目介绍 三.技术问题一般会问理论流程还有基础知识包括团队能力怎么样 四.HR常问面试题 五.最后一个问题 六.总结 随着企业对于软件质量的重视,软件测试工程师倍受 ...
- 弹性布局(Flex)布局介绍
Flex是Flexible Box的缩写,意为"弹性布局".任何一个容器都可以指定为Flex布局,块级元素为display:block,行内元素为display:inline-fl ...
- Css 弹性布局(Flex)详细介绍(Flex 属性详解、场景分析)
目录 前言 Flex 布局是什么? Flex 简介 Flex 容器属性 Flex 基本使用 场景一 flex-direction 场景二 justify-content align-it ...
最新文章
- 打印机扫描后旋转纸张_档案扫描好帮手,富士通ix1500无线双面高速扫描仪评测...
- PlanAhead 与时序分析
- php sql 条件拼组_ThinkPHP框架SQL操作链式写法原理(浅显易懂)
- git安装与配置_git 安装及基本配置
- C# action,delegate,func的用法和区别
- PyTorch | 保存和加载模型教程
- 安装,使用node和npm,切换镜像源cnpm
- perl 字符串删除末尾几个字符_perl中的字符串操作函数chomp与chop介绍
- Flink Exactly-Once 投递实现浅析 一致性
- python输出偶数_Python习题册028:输出列表中的偶数
- 姚前:分布式账本与传统账本的异同及其现实意义
- MySQL修改数据表中的字段名_MySQL修改数据表中的字段名
- C#路径中使用斜杠/和反斜杠\的区别
- oracle数据库综合练习题及答案写法
- MacOs使用IDEA自带的maven教程
- Android 11.0 12.0系统默认授予读写权限给第三方app
- 3DMM(3D Morphable Model)原理和实现
- 企业微信hook接口,朋友圈功能开发教程,逆向开发,企业微信营销开发
- 基于.NET 制作一个气象站 IoT 应用
- elasticsearch ik pingyin 分词器的安装和使用
热门文章
- html表格隐藏筛选框,jQuery表格筛选插件XLS TableFilter
- 超详细!XGBoost原理介绍
- 如何挂载NFS(一)
- Unity Mesh基础系列(三)立方体球(更好更圆)
- npm install 安装和卸载
- Oracle的学习心得和知识总结(六)|Oracle数据库同义词技术详解
- java.lang.OutOfMemoryError: PermGen space基于idea,MyEclipse或tomcat的详细解决方法以及详解JVM配置参数
- IntelliJ IDEA开发最佳配置(已更新至2022版)
- 【Python之路】特别篇--Git GitHub
- 福建师范计算机应用基础考试内容,关于印发《福建师范大学 课程教学改革实施方案(试行)》的通知...