雷达智富

首页 > 内容 > 程序笔记 > 正文

程序笔记

Polly重试回退熔断策略组合示例

2024-09-08 13

Polly重试回退熔断策略组合示例

假设服务A是一个集群(2个节点),首先调用其中一个节点的服务,如果失败或者超时,则用轮询的方式进行重试调用。

重试多次仍然失败,则直接返回一个替代数据(服务降级),之后一段时间,服务被熔断。再熔断时间内,所有对该服务的调用都以替代数据返回。

熔断时间过后,尝试再次调用,如果成功,则关闭熔断器,服务通道打通。否则,继续熔断这个服务一段时间。

要用到几个策略?超时策略,重试策略,断路器策略,回退策略(降级),策略组合。

实现代码如下

namespace ConsulTest
{
    public class PolicyBuilder
    {
        public static ISyncPolicy CreatePolly() {
            // 超时1秒
            var timeoutPolicy = Policy.Timeout(1, (context, timespan, task) => {
                Console.WriteLine("执行超时,抛出TimeoutRejectedException异常");
            });
            // 重试2次
            var retryProlicy = Policy.Handle<Exception>().WaitAndRetry(2,
                retryAttempt => TimeSpan.FromSeconds(2),
                (exception, timespan, retryCount, context) => {
                    Console.WriteLine($"{DateTime.Now} = 重试 {retryCount} 次 - 抛出{exception.GetType()}");
                });
            // 连续发生两次故障,就熔断3秒
            var circuitBreakerPolicy = Policy.Handle<Exception>().CircuitBreaker(
                // 熔断前允许出现几次错误
                2,
                // 熔断时间
                TimeSpan.FromSeconds(3),
                // 熔断时触发
                onBreak: (ex, breakDelay) =>
                {
                    Console.WriteLine($"{DateTime.Now} - 断路器:开启状态(熔断时触发)");
                },
                // 熔断回恢复时触发
                onReset:()=> {
                    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()}");
            });
            // 策略从右到左依次进行调用
            return Policy.Wrap(fallbackPolicy, circuitBreakerPolicy, retryProlicy, timeoutPolicy);
        }
    }
}

测试代码如下,服务注册和服务发现代码可以参考

.NET Core Consul服务注册

.NET Core Consul服务发现

Polly瞬态故障处理熔断降级用法

namespace ConsulTest
{
    public class ConsulBasic
    {
        public static void Run() {
            var serviceProvider = new ConsulServiceProvider(new Uri("http://192.168.31.175:8500"));
            var aspNetCoreService = serviceProvider.CreateServiceBuilder(builder => {
                builder.ServiceName = "AspNetCore";
                builder.LoadBalancer = TypeLoadBalancer.RoundRobinLoad;//可选RandomLoad
                builder.UriScheme = Uri.UriSchemeHttp;
            });
            var httpClient = new HttpClient();
            var policy = PolicyBuilder.CreatePolly();
            for (int i = 0; i < 100; i++)
            {
                Console.WriteLine($"----------第{i}次请求-----------");
                policy.Execute(() => {
                    try
                    {
                        var uri = aspNetCoreService.BuildAsync("/Health").Result;
                        Console.WriteLine($"{DateTime.Now} - 正在调用:{uri}");
                        var content = httpClient.GetStringAsync(uri).Result;
                        Console.WriteLine($"返回结果:{content}");
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("调用异常:"+ex.GetType());
                        // 如果你要在策略里捕捉异常,如果这个异常还是你定义的故障,一定要把这个异常抛出来
                        throw ex;
                    }
                });
                Task.Delay(500).Wait();
            }
            Console.ReadLine();
        }
    }
}

我关闭两个服务,并且运行程序,结果如下

可以看到

首先判断调用是否超时,如果超时就会触发异常,发生超时故障,然后就触发重试策略

如果重试两次中只要成功一次,就直接返回调用结果

如果重试两次都失败,第三次再次失败,就会发生故障

重试之后是断路器策略,所以这个故障会被断路器接收,当断路器收到两次故障,就会触发熔断,也就是说断路器开启

断路器开启的3秒内,任何故障或者操作,都会通过断路器到达回退策略,触发降级操作

3秒后,断路器进入到半开启状态,操作可以正常执行

接下来我开启一个服务,运行结果如下

在断路器半开启状态时,调用服务成功了,于是断路器被关闭了。

更新于:8天前
赞一波!

文章评论

全部评论