Polly极简介绍

Polly是一个被.NET基金会认可的弹性和瞬态故障处理库,允许我们以非常顺畅和线程安全的方式来执诸如行重试,断路,超时,故障恢复等策略,其主要功能如下:

  • 重试(Retry)
  • 断路器(Circuit-Breaker)
  • 超时检测(Timeout)
  • 缓存(Cache)
  • 降级(Fallback)

Polly的策略主要由“故障”和“动作”两个部分组成,“故障”可以包括异常、超时等情况,“动作”则包括Fallback(降级)、重试(Retry)、熔断(Circuit-Breaker)等。策略则用来执行业务代码,当业务代码出现了“故障”中的情况时就开始执行“动作”。

Polly 错误处理使用三步曲

  • 定义条件: 定义你要处理的错误异常或返回结果
  • 定义处理方式 : 重试、熔断、回退
  • 执行

定义条件

  • 定义异常错误的条件
            // 单个异常类型Policy.Handle<Exception>();// 限定条件的单个异常Policy.Handle<Exception>(ex => ex.Message == "请求超时");// 多个异常类型Policy.Handle<Exception>().Or<ArgumentException>();// 限定条件的多个异常Policy.Handle<Exception>(ex => ex.Message == "请求超时").Or<ArgumentException>(ex => ex.ParamName == "ID");// Inner Exception 异常里面的异常类型 Policy.HandleInner<Exception>().OrInner<ArgumentException>(ex => ex.ParamName == "ID");
  • 定义返回结果的条件
            // 返回结果加限定条件 Policy.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.NotFound);// 处理多个返回结果Policy.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.InternalServerError).OrResult(r => r.StatusCode == HttpStatusCode.BadGateway);// 处理元类型结果 (用.Equals)Policy.HandleResult(HttpStatusCode.InternalServerError).OrResult(HttpStatusCode.BadGateway);

定义处理方式

重试

重试很好理解,当发生某种错误或者返回某种结果的时候进行重试

  • 按次数重试
            // 重试1次Policy.Handle<Exception>().Retry();// 重试3次Policy.Handle<Exception>().Retry(3);// 重试3次,加上重试时的action参数Policy.Handle<Exception>().Retry(3, (exception, retryCount) =>{// do something});
  • 不断重试(直到成功)
            // 不断重试,直到成功Policy.Handle<Exception>().RetryForever();// 不断重试,带action参数在每次重试的时候执行Policy.Handle<Exception>().RetryForever(exception =>{// do something       });
  • 等待之后按次数重试
            // 重试3次,每次等待5sPolicy.Handle<Exception>().WaitAndRetry(3,retryAttempt => TimeSpan.FromSeconds(5),// 处理异常、等待时间、重试第几次(exception, timespan, retryCount, context) =>{// do something});// 重试3次,分别等待1、2、3秒。Policy.Handle<Exception>().WaitAndRetry(new[]{TimeSpan.FromSeconds(1),TimeSpan.FromSeconds(2),TimeSpan.FromSeconds(3)});

熔断

熔断也可以被作为当遇到某种错误场景下的一个操作。

  • 打开(Open)——熔断器打开状态,此时对目标服务的调用都直接返回错误,熔断周期内不会走网络请求,当熔断周期结束时进入半开状态;
  • 关闭(Closed)——关闭状态下正常发生网络请求,但会记录符合熔断条件的连续执行次数,如果错误数量达到设定的阈值(如果在没有达到阈值之前恢复正常,之前的累积次数将会归零),熔断状态进入到打开状态;
  • 半开(Half-Open)——半开状态下允许定量的服务请求,如果调用都成功则认为恢复了,关闭熔断器,否则认为还没好,又回到熔断器打开状态;
Policy.Handle<Exception>().CircuitBreaker(// 熔断前允许出现几次错误3,// 熔断时间TimeSpan.FromSeconds(5),// 熔断时触发onBreak: (ex, breakDelay) =>{Console.WriteLine("断路器:开启状态(熔断时触发)");},// 熔断恢复时触发onReset: () =>{Console.WriteLine("断路器:关闭状态(熔断恢复时触发)");},// 熔断时间到了之后触发,尝试放行少量(1次)的请求,onHalfOpen: () =>{Console.WriteLine("断路器:半开启状态(熔断时间到了之后触发)");});

超时检测(Timeout)

Polly中关于超时的两个策略:一个是悲观策略(Pessimistic),一个是乐观策略(Optimistic)。其中,悲观策略超时后会直接抛异常,而乐观策略则不会,而只是触发CancellationTokenSource.Cancel函数,需要等待委托自行终止操作。一般情况下,我们都会用悲观策略。

            // 设置超时时间为30sPolicy.Timeout(30, onTimeout: (context, timespan, task, ex) =>{// do something });// 超时分为乐观超时与悲观超时,乐观超时依赖于CancellationToken ,它假设我们的具体执行的任务都支持CancellationToken。// 那么在进行timeout的时候,它会通知执行线程取消并终止执行线程,避免额外的开销。下面的乐观超时的具体用法 。HttpResponseMessage httpResponse = await Policy.TimeoutAsync(30).ExecuteAsync(async ct => await new HttpClient().GetAsync(""),CancellationToken.None);// 悲观超时与乐观超时的区别在于,如果执行的代码不支持取消CancellationToken,// 它还会继续执行,这会是一个比较大的开销。Policy.Timeout(30, TimeoutStrategy.Pessimistic);

舱壁

它用来限制某一个操作的最大并发执行数量

            Policy.Bulkhead(12);// 同时,我们还可以控制一个等待处理的队列长度Policy.Bulkhead(12, 2);// 以及当请求执行操作被拒绝的时候,执行回调Policy.Bulkhead(12, context =>{// do something });

回退(Fallback)

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

            Policy.Handle<Exception>().Fallback(() =>{// do something});

组合Polly

使用Wrap方法,将多个policy组合起来,其中策略的优先级是右到左。

 var policyWrap = Policy.Wrap(fallback, breaker, timeout, retry, bulkhead);policyWrap.Execute(() =>{// do something});

Polly测试项目

  • 添加一个控制台项目,Nuget添加Polly引用
  • 添加创建组合polly代码
public static ISyncPolicy CreatePolly(){// 超时1秒var timeoutPolicy = Policy.Timeout(1, TimeoutStrategy.Pessimistic, (context, timespan, task) =>{Console.WriteLine("执行超时,抛出TimeoutRejectedException异常");});// 重试2次var retryPolicy = Policy.Handle<Exception>().WaitAndRetry(2,retryAttempt => TimeSpan.FromSeconds(2),(exception, timespan, retryCount, context) =>{Console.WriteLine($"{DateTime.Now} - 重试 {retryCount} 次 - 抛出{exception.GetType()}-{timespan.TotalMilliseconds}");});// 连续发生两次故障,就熔断3秒var circuitBreakerPolicy = Policy.Handle<Exception>().CircuitBreaker(// 熔断前允许出现几次错误2,// 熔断时间TimeSpan.FromSeconds(5),// 熔断时触发 OPENonBreak: (ex, breakDelay) =>{Console.WriteLine($"{DateTime.Now} - 断路器:开启状态(熔断时触发)");},// 熔断恢复时触发 // CLOSEonReset: () =>{Console.WriteLine($"{DateTime.Now} - 断路器:关闭状态(熔断恢复时触发)");},// 熔断时间到了之后触发,尝试放行少量(1次)的请求,onHalfOpen: () =>{Console.WriteLine($"{DateTime.Now} - 断路器:半开启状态(熔断时间到了之后触发)");});// 回退策略,降级!var fallbackPolicy = Policy.Handle<Exception>().Fallback(() =>{Console.WriteLine("这是一个Fallback");}, exception =>{Console.WriteLine($"Fallback异常:{exception.GetType()}");});// 策略从右到左依次进行调用// 首先判断调用是否超时,如果超时就会触发异常,发生超时故障,然后就触发重试策略;// 如果重试两次中只要成功一次,就直接返回调用结果// 如果重试两次都失败,第三次再次失败,就会发生故障// 重试之后是断路器策略,所以这个故障会被断路器接收,当断路器收到两次故障,就会触发熔断,也就是说断路器开启// 断路器开启的3秒内,任何故障或者操作,都会通过断路器到达回退策略,触发降级操作// 3秒后,断路器进入到半开启状态,操作可以正常执行return Policy.Wrap(fallbackPolicy, circuitBreakerPolicy, retryPolicy, timeoutPolicy);}
  • 添加测试代码
            var policy = CreatePolly();for (int i = 0; i < 100; i++){Console.WriteLine($"-------------第{i}次请求-------------");policy.Execute(() =>{// 从10次开始,正常请求成功if (i < 10){Thread.Sleep(3000);}else{Console.WriteLine($"{DateTime.Now}:请求成功");}});Thread.Sleep(1000);}
  • 测试效果如下图:

    示例代码

.net core微服务入门之Polly相关推荐

  1. .Net Core微服务入门——Ocelot API网关接入(二)

    Net Core微服务入门--Ocelot API网关接入(二) 我们先接入Consul,实现服务发现 服务发现 1.引入 Ocelot.Provider.Consul 包 2.修改ocelot.js ...

  2. swagger 返回json字符串_Net Core微服务入门全纪录(完结)——Ocelot与Swagger

    前言 上一篇[.Net Core微服务入门全纪录(八)--Docker Compose与容器网络]完成了docker-compose.yml文件的编写,最后使用docker compose的一个up指 ...

  3. .net core ocelot 获取路由的mothed_Net Core微服务入门全纪录(四)Ocelot网关(上)

    上一篇[.Net Core微服务入门全纪录(三)--Consul-服务注册与发现(下)]已经使用Consul完成了服务的注册与发现,实际中光有服务注册与发现往往是不够的,我们需要一个统一的入口来连接客 ...

  4. .Net Core微服务入门全纪录(完结)——Ocelot与Swagger

    点击上方蓝字"小黑在哪里"关注我吧 前言 上一篇[.Net Core微服务入门全纪录(八)--Docker Compose与容器网络]完成了docker-compose.yml文件 ...

  5. .Net Core微服务入门——Ocelot和Consul集群高可用

    .Net Core微服务入门--Ocelot和Consul集群高可用 上一章 我们ocelot网关顺利的接入了consul集群,并且访问成功. 但是,我们也遇到了问题,把 192.168.8.25 上 ...

  6. .Net Core微服务入门——Ocelot API网关接入(一)

    .Net Core微服务入门--Ocelot API网关接入 上一章我们测试了一个简单的Client 端访问Consul实现服务注册与发现,但是现实生产环境我们直接通过Client自行连接Consul ...

  7. .NET Core微服务之基于Ocelot实现API网关服务(续)

    Tip: 此篇已加入.NET Core微服务基础系列文章索引 一.负载均衡与请求缓存 1.1 负载均衡 为了验证负载均衡,这里我们配置了两个Consul Client节点,其中ClientServic ...

  8. .NET Core微服务之基于Ocelot实现API网关服务

    一.啥是API网关? API 网关一般放到微服务的最前端,并且要让API 网关变成由应用所发起的每个请求的入口.这样就可以明显的简化客户端实现和微服务应用程序之间的沟通方式.以前的话,客户端不得不去请 ...

  9. .NET Core微服务之路:文章系列和内容索引汇总 (v0.52)

    原文:.NET Core微服务之路:文章系列和内容索引汇总 (v0.52) 微服务架构,对于从事JAVA架构的童鞋来说,早已不是什么新鲜的事儿,他们有鼎鼎大名的Spring Cloud这样的全家桶框架 ...

最新文章

  1. ecshop简单三部实现导航分类二级菜单
  2. 相关疑惑解决,java线程虚假唤醒等等问题
  3. @slf4j注解_SpringBoot + Redis + 注解 + 拦截器 实现接口幂等性校验
  4. 前端学习(1874)vue之电商管理系统电商系统之修改element-ui组件的按需导入
  5. C++即时通讯实现原理及常见问题
  6. access month函数用法_小白进阶必备的10组函数公式实用技巧解读,有案例和详情解读哦!...
  7. maven缺少依赖包,强制更新命令
  8. 编译原理基础---思维导图
  9. mvn exec: java_实战|Java 测试覆盖率 Jacoco插桩的不同形式总结和踩坑记录(下)
  10. [NOIp2016]天天爱跑步 线段树合并
  11. 高德定位html,Ionic3 高德Web定位
  12. 艾伟_转载:在C#中实现3层架构
  13. H - 数论中的异或 HRBUST - 1688
  14. 【设计】全差分设计报告
  15. f和摄氏度怎么换算_华氏度怎么换算成摄氏度啊?
  16. 单片机内存及运行原理
  17. minikube start命令的国内使用方法
  18. Relay和Rendezvous
  19. Java8新特性 方法引用(二)
  20. Xcode 报错 ERROR ITMS-90096

热门文章

  1. Python爬虫实战Pro | (1) 爬取猫眼电影Top100榜单
  2. 微信小程序入门(保姆级)
  3. 实验一 201521440022 祁浩然
  4. VS安装扩展缓慢问题解决
  5. 使用stunnel双向证书认证加密samba的数据传输
  6. edgex制作自己的树莓派镜像
  7. 判断二叉树是否为排序二叉树
  8. php动态页面如何缓存,php缓存并压缩动态页面的技巧详解
  9. 架构面试精讲第三节 分布式技术RPC、MQ、Redis、Mysql、restful详解
  10. 第五十五周总结——十一月月底总结