ASP.NET Core 微服务初探[2]:熔断降级之Polly (3)

再定义一个熔断策略:

var circuitBreakerPolicy = Policy.Handle<HttpRequestException>().Or<TimeoutException>().Or<TimeoutRejectedException>() .CircuitBreakerAsync( // 熔断前允许出现几次错误 exceptionsAllowedBeforeBreaking: 2, // 熔断时间 durationOfBreak: TimeSpan.FromSeconds(3), // 熔断时触发 onBreak: (ex, breakDelay) => { Console.WriteLine(DateTime.Now.ToString() + "Breaker->Breaking the circuit for " + breakDelay.TotalMilliseconds + "ms! Exception: ", ex.Message); }, // 熔断恢复时触发 onReset: () => { Console.WriteLine(DateTime.Now.ToString() + "Breaker->Call ok! Closed the circuit again."); }, // 在熔断时间到了之后触发 onHalfOpen: () => { Console.WriteLine(DateTime.Now.ToString() + "Breaker->Half-open, next call is a trial."); } );

如上,连续错误2次就熔断3秒。

最后,再定义一个回退策略:

var fallbackPolicy = Policy<string>.Handle<Exception>() .FallbackAsync( fallbackValue: "substitute data", onFallbackAsync: (exception, context) => { Console.WriteLine("It's Fallback, Exception->" + exception.Exception.Message + ", return substitute data."); return Task.CompletedTask; });

我们的业务代码如下:

private List<string> services = new List<string> { "localhost:5001", "localhost:5002" }; private int serviceIndex = 0; private HttpClient client = new HttpClient(); private Task<string> HttpInvokeAsync() { if (serviceIndex >= services.Count) { serviceIndex = 0; } var service = services[serviceIndex++]; Console.WriteLine(DateTime.Now.ToString() + "-Begin Http Invoke->" + service); return client.GetStringAsync("http://" + service + "/api/values"); }

这里方便测试,直接写死了两个服务,对其轮询调用,在生产环境中可以参考上一篇《服务发现之Consul》来实现服务发现和负载均衡。

现在,我们组合这些策略来调用我们的业务代码:

for (int i = 0; i < 100; i++) { Console.WriteLine(DateTime.Now.ToString() + "-Run[" + i + "]-----------------------------"); var res = await fallbackPolicy.WrapAsync(Policy.WrapAsync(circuitBreakerPolicy, retryPolicy, timeoutPolicy)).ExecuteAsync(HttpInvokeAsync); Console.WriteLine(DateTime.Now.ToString() + "-Run[" + i + "]->Response" + ": Ok->" + res); await Task.Delay(1000); Console.WriteLine("--------------------------------------------------------------------------------------------------------------------"); }

如上,循环执行100次,策略的执行是非常简单的,唯一需要注意的就是调用的顺序:如上是依次从右到左进行调用,首先是进行超时的判断,一旦超时就触发TimeoutRejectedException异常,然后就进入到了重试策略中,如果重试了一次就成功了,那就直接返回,不再触发其他策略,否则就进入到熔断策略中:

breaking

如上图,服务A(localhost:5001)和服务B(localhost:5001),都没有启动,所以会一直调用失败,最后熔断器开启,并最终被降级策略拦截,返回substitute data。

现在我们启动服务A,可以看到服务会自动恢复,解除熔断状态:

reset

总结

本篇首先讲解了一下微服务中熔断、降级的基本概念,然后对.Net Core中的Polly框架做了一个基本介绍,最后基于Polly演示了如何在.NET Core中实现熔断降级来提高服务质量。而熔断本质上只是一个保护壳,在周围出现异常的时候保全自身,从长远来看,平时定期做好压力测试才能防范于未然,降低触发熔断的次数。如果清楚的知道每个服务的承载量,并做好服务限流的控制,就能将“高压”下触发熔断的概率降到最低了。那下一篇就来介绍一下速率限制(Rate Limiting),敬请期待!

附本篇示例源码地址:https://github.com/RainingNight/AspNetCoreSample/tree/master/src/Microservice/CircuitBreaker/PollyDemo。

参考资料

The Network is Reliable

App-vNext/Polly Wiki

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zywpwf.html