Polly失败重试

使用组件包
Polly
Polly.Extensions.Http
Microsoft.Extensions.Http.Polly
Polly策略功能

1、失败重试

调用失败的时候,重新尝试操作

方法:retry(重试次数,一直重试,等待事件后重试)

 

 

2、服务熔断

部分服务不可用的时候,应用可以快速响应一个熔断的结果,这样熔断的应用就不会一直被请求。从而不会是不可用服务一直被请求从而是整个应用服务崩溃。

方法:CircuitBreaker

 

 发生10以异常,熔断10秒钟

            services.AddHttpClient("orderclientv3").AddPolicyHandler(Policy<HttpResponseMessage>.Handle<HttpRequestException>().CircuitBreakerAsync(
                handledEventsAllowedBeforeBreaking: 10,
                durationOfBreak: TimeSpan.FromSeconds(10),
                onBreak: (r, t) => { },
                onReset: () => { },
                onHalfOpen: () => { }
                ));

高级用法,跟进失败比例。  80%出错就熔断, 第二个参数  多长时间内出现80%错误,第三个参数  当请求比较少时候,最少的请求数,下面就是  10秒内 请求小于100个就还不需要熔断。第四个参数 熔断时间长度

            services.AddHttpClient("orderclientv3").AddPolicyHandler(Policy<HttpResponseMessage>.Handle<HttpRequestException>().AdvancedCircuitBreakerAsync(
                failureThreshold: 0.8,
                samplingDuration: TimeSpan.FromSeconds(10),
                minimumThroughput: 100,
                durationOfBreak: TimeSpan.FromSeconds(20),
                onBreak: (r, t) => { },
                onReset: () => { },
                onHalfOpen: () => { }));

 

应用程序熔断的时候会抛出一个异常  BrokenCircuitException。这个异常可以让后续策略使用。比如说  熔断后  在降级

 

 

 

 

3、超时处理

我们给服务设置一个超时时间,如果超过时间。就按照我们设定的返回,比如说一个缓存的结果。

方法:Timeout

 

 

 

 

 

4、舱壁隔离

实际上是一个限流的功能,为服务定义最大的流量和队列,控制请求量过大而被压崩。

方法:Bulkhead

 

 

限流抛出异常  BulkheadRejectedException,可以供后续策略使用

 

 

 

5、缓存策略

类似于AOP的机制为应用嵌入缓存。当缓存命中快速响应换存,而不是每次都请求服务。

方法:Cache

 

 

 

 

 

6、失败降级  也叫  回退

当我的服务不可用的时候,我们响应一个更加友好的结果,而不是报错。

方法:FallBack

 

 

 

 

7、组合策略

可以将上面的策略组合在一起

我们将超时策略(Timeout)加上回退(FallBack)策略组合使用

 

 

Polly使用步骤
• 定义要处理的异常类型或返回值
• 定义要处理动作(重试、熔断、降级响应等)
• 使用定义的策略来执行代码
失败重试场景
1、服务失败是暂时的,可以自愈的。
比如说网络闪断
服务的部分结点不可用
2、服务是幂等的,重复调用不会有副作用
最佳实践
1、设置失败重试次数
2、设置带有步长策略的失败等待时间
3、设置降级响应
重试次数达到某个值,就应该让服务降级
4、设置断路器
重试很多次还是不可用,就要短路了。这就是熔断
HttpClient
            services.AddGrpcClient<OrderGrpc.OrderGrpcClient>(options =>
            {
                options.Address = new Uri("https://localhost:5001");
            }).ConfigurePrimaryHttpMessageHandler(provider =>
            {
                var handler = new SocketsHttpHandler();
                handler.SslOptions.RemoteCertificateValidationCallback = (a, b, c, d) => true; //允许无效、或自签名证书
                return handler;
            }).AddTransientHttpErrorPolicy(t => t.RetryAsync(3));
            //1、对HttpRequestException 500 408这样的错误会执行

            #region 2、策略
            #region 定义策略
            //服务中注册策略
            var reg= services.AddPolicyRegistry();
            //捕捉到异常HttpResponseMessage 且  响应码是BadRequest ,重试3次 
            reg.Add("Retry3", Policy.HandleResult<HttpResponseMessage>(message => { return message.StatusCode == System.Net.HttpStatusCode.BadRequest; }).RetryAsync(3));


            //服务中注册策略
            var reg2 = services.AddPolicyRegistry();
            //捕捉到异常HttpResponseMessage 且  NotFound  ,直接返回ok
            reg.Add("RetryBack", Policy.HandleResult<HttpResponseMessage>(message => { return message.StatusCode == System.Net.HttpStatusCode.NotFound; }).Fallback(new HttpResponseMessage() { StatusCode=System.Net.HttpStatusCode.OK}));
            #endregion

            #region 使用策略
            services.AddHttpClient("client1").AddPolicyHandlerFromRegistry("Retry3");

            //动态定义策略机制
            services.AddHttpClient("client2").AddPolicyHandlerFromRegistry((reg,mes)=> {
                //这行代码意思如果是httpget 就使用Retry3策略,  如果不是就熔断不做任何处理
                //
                return mes.Method == HttpMethod.Get ? reg.Get<IAsyncPolicy<HttpResponseMessage>>("Retry3") : Policy.NoOpAsync<HttpResponseMessage>();
            });
            #endregion
            #endregion

            #region 3、捕获异常操作
            //直接返回
            //Policy.Handle<Exception>().Fallback()
            //熔断
            //Policy.Handle<Exception>().CircuitBreaker
            #endregion
View Code

上面代码主要指结合httpclient添加polly


策略分类
• 被动策略(异常处理、结果处理)
程序出现异常,策略被动去做
 
• 主动策略(超时处理、断路器、舱壁隔离、缓存)
策略总动去做的
策略状态

 

 使用策略的时候,策略设置为单例的模式,但是这些策略是有状态的。

比如要对多个服务的熔断计数,那就需要多个熔断策略实例。

策略组合  熔断-降级
            var breakPolicy = Policy<HttpResponseMessage>.Handle<HttpRequestException>().AdvancedCircuitBreakerAsync(
                failureThreshold: 0.8,
                samplingDuration: TimeSpan.FromSeconds(10),
                minimumThroughput: 100,
                durationOfBreak: TimeSpan.FromSeconds(20),
                onBreak: (r, t) => { },
                onReset: () => { },
                onHalfOpen: () => { });

            var message = new HttpResponseMessage()
            {
                Content = new StringContent("{}")
            };
            var fallback = Policy<HttpResponseMessage>.Handle<BrokenCircuitException>().FallbackAsync(message);
            var retry = Policy<HttpResponseMessage>.Handle<Exception>().WaitAndRetryAsync(3, i => TimeSpan.FromSeconds(1));
            var fallbackBreak = Policy.WrapAsync(fallback, retry, breakPolicy);
            services.AddHttpClient("httpv3").AddPolicyHandler(fallbackBreak);

1、上面代码组合策略。    熔断-重试-降级

10内有80%的错误请求,就熔断。熔断后重试三次,如果服务正常,则按正常处理,如果失败 则(降级)后返回一个空的http返回。
----------------------------------------------------------------------------------------------------------------
            var bulk = Policy.BulkheadAsync<HttpResponseMessage>(
                //最大并发 处理 数量
                maxParallelization: 30,
                //如果不定义这个参数, 最大请求数超量,就会报错。定义了这个参数其他请求就会排队,如果排队大于20就在报错 
                maxQueuingActions: 20,
                //当我们请求被拒绝,被限流了  做的处理
                onBulkheadRejectedAsync: contxt => Task.CompletedTask
                );

            var message2 = new HttpResponseMessage()
            {
                Content = new StringContent("{}")
            };
            var fallback2 = Policy<HttpResponseMessage>.Handle<BulkheadRejectedException>().FallbackAsync(message);
            var fallbackbulk = Policy.WrapAsync(fallback2, bulk);
            services.AddHttpClient("httpv4").AddPolicyHandler(fallbackbulk);

2、上面代码组合策略。    限流-降级

 
posted @ 2020-06-23 00:48  西伯利亚的狼  阅读(690)  评论(0编辑  收藏  举报