2020-07-28
417 0Polly是一个被.NET基金会认可的弹性和瞬态故障处理库,允许我们以非常顺畅和线程安全的方式来执诸如行重试,断路,超时,故障恢复等策略,其主要功能如下:重试(Retry)断路器(Circuit-Breaker)超时检测(Timeout)缓存(Cache)降级(Fallback)。
首先通过NuGet安装Polly,我当前使用的是最新7.2.1版本的Polly。
Polly的基本使用方法:定义故障,当发生了HttpRequestException异常的时候,就会触发策略。指定策略。
以下示例代码,定义了在执行某业务代码时如果出现HttpRequestException异常就是出现故障,会触发降级策略。
Policy.Handle<HttpRequestException>(). Fallback(()=> { // 降级方法 }).Execute(()=> { // 业务方法,一般是跨服务的调用,可以合HttpClient结合使用 throw new HttpRequestException(); });
Polly故障的定义方法
// 单个异常的故障 Policy.Handle<Exception>(); // 带条件的异常类型 Policy.Handle<Exception>(ex => ex.Message.Contains("xxx")); // 多个异常类型带条件 Policy.Handle<HttpRequestException>(ex => ex.Message.Contains("xxx")) .Or<ArgumentException>() .Or<NetworkInformationException>();
注意:Polly是故障处理库,一般定义服务调用环节产生的不可控的异常作为故障(请求出错等不可控的异常)。业务代码出现异常不需要Polly。
Polly弹性策略
// 默认重试一次 Policy.Handle<Exception>().Retry();//.Execute(() => { }); // 重试N次 Policy.Handle<Exception>().Retry(3, (ex, i) => { //委托,可以做一些日志记录等操作 }); // 无限重试直到成功(不推荐) Policy.Handle<Exception>().RetryForever(); // 重试且等待 Policy.Handle<Exception>().WaitAndRetry(new[] { TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1) }); // 重试且等待2的i(次数)次方 Policy.Handle<Exception>().WaitAndRetry(3, i => TimeSpan.FromSeconds(Math.Pow(2, i))); // 每一种策略最后一个参数都是一个委托,这个委托就是异常委托 // 断路器,非常使用的策略 // 连续触发了指定(2)次数的故障后,就开启断路器(OPEN),进入熔断状态,1分钟 // 断路器有三种状态,OPEN CLOSED HALF-OPEN var breaker = Policy.Handle<HttpRequestException>().CircuitBreaker(2, TimeSpan.FromMinutes(1), (exception,span)=> { },//OPEN 断路器开启 ()=> { });//CLOSE 断路器关闭 //breaker.CircuitState = Polly.CircuitBreaker.CircuitState.Closed; //breaker.CircuitState = Polly.CircuitBreaker.CircuitState.HalfOpen; //breaker.CircuitState = Polly.CircuitBreaker.CircuitState.Open; // 这个不是断路器模式的状态,这个是Polly断路器策略里的一种特殊状态 // 手动的打开断路器,断路器:手动开启状态 //breaker.CircuitState = Polly.CircuitBreaker.CircuitState.Isolated; // 手动开启断路器,断路器默认是关闭的 breaker.Isolate(); // 手动关闭断路器 breaker.Reset(); // 如果再故障采样持续时间内,导致处理异常的操作的比例超过故障阈值,则发生熔断 // 前提是再次期间,通过断路器的操作的数量至少是最小吞吐量 Policy.Handle<HttpRequestException>().AdvancedCircuitBreaker( 0.5,// 故障阈值,50% TimeSpan.FromSeconds(10),// 故障采样时间,10秒 8,// 最小吞吐量,10秒内最少执行了8次操作 TimeSpan.FromSeconds(30)// 熔断时间,30秒 ); // 熔断30秒后,变成HALF-OPEN,半开启状态, // 断路器会尝试着释放(1次)操作,如果成功就变成CLOSE,如果失败断路器打开OPEN(30秒) // 超时,服务调用慢也是故障,自己定义n秒 // 不会用单独策略,只会用策略组合 // 超时不需要定义故障 Policy.Timeout(3, (context, span, arg3, arg4) => { // arg4 is TimeoutRejectedException // 委托可选 }).Execute(() => { }); // 舱壁隔离,通过控制并发数量来管理负载。主动式策略也不需要定义故障 // 最大并发数12,超过12的都拒绝掉 Policy.Bulkhead(12).Execute(()=> { }); // 超过12个的最多20个等待 Policy.Bulkhead(12,20).Execute(() => { }); // 缓存比较复杂,以来其他库,集合Redis // Policy.Cache()
Polly策略包装 策略组合
// 降级策略 var fullback = Policy.Handle<Exception>(). Fallback(() => { Console.WriteLine("Polly Fallback!"); }); // 重试策略 var retry = Policy.Handle<Exception>().Retry(3, (ex, i) => { Console.WriteLine($"retryCount:{i}"); //委托,可以做一些日志记录等操作 }); // 如果重试3次仍然发生故障就降级 var policy = Policy.Wrap(fullback, retry); policy.Execute(() => { Console.WriteLine("Polly Begin"); throw new Exception("Error"); });
策略组合运行结果: