zoukankan      html  css  js  c++  java
  • 再探Circuit Breaker之使用Polly

    前言

    上一篇介绍了使用Steeltoe来处理服务熔断,这篇我们将用Polly来处理服务熔断。

    不废话了,直接进正题。

    简单的例子

    同样先定义一个简单的服务。

    [Route("api/[controller]")]
    public class ValuesController : Controller
    {
        // GET api/values
        [HttpGet]
        public string Get()
        {
            return "service--a";
        }
    }
    

    再来一个新服务去调用上面的服务。

    定义一个用于访问服务的Service接口和实现。

    public interface IAService
    {
        Task<string> GetAsync();
    }
    
    public class AService : IAService
    {
        private PolicyWrap<string> _policyWrap;
    
        private ILogger _logger;
    
        public AService(ILoggerFactory loggerFactory)
        {
            _logger = loggerFactory.CreateLogger<AService>();
    
            //超时
            var timeout = Policy
                  .TimeoutAsync(1, Polly.Timeout.TimeoutStrategy.Pessimistic, (context, ts, task) =>
                  {
                      _logger.LogInformation("AService timeout");
                      return Task.CompletedTask;
                  });
            
            //熔断
            var circuitBreaker = Policy
                .Handle<Exception>()
                .CircuitBreakerAsync(2, TimeSpan.FromSeconds(5), (ex, ts) =>
                {
                    _logger.LogInformation($"AService OnBreak -- ts = {ts.Seconds}s ,ex.message = {ex.Message}");
                }, () =>
                {
                    _logger.LogInformation("AService OnReset");
                });
            
            //Fallback + 熔断 + 超时
            _policyWrap = Policy<string>
                .Handle<Exception>()
                .FallbackAsync(GetFallback(), (x) =>
                {
                    _logger.LogInformation($"AService Fallback -- {x.Exception.Message}");                    
                    return Task.CompletedTask;
                })
                .WrapAsync(circuitBreaker)
                .WrapAsync(timeout);
        }
    
        //降级处理
        private string GetFallback()
        {
            return "fallback";
        }
    
        public async Task<string> GetAsync()
        {
            return await _policyWrap.ExecuteAsync(() =>
            {
                return QueryAsync();
            });
        }
    
        private async Task<string> QueryAsync()
        {
            using (var client = new HttpClient())
            {
                var res = await client.GetStringAsync("http://localhost:9001/api/values");
                return res;
            }
        }
    }
    

    要注意的有几个地方。

    Polly没有既包含熔断又包含降级又包含超时的,这个需要自己去组合。相对来说,Hystrix在这一方面似乎好一点点。

    但是,各有各的好,Polly分离了每一个模块,让我们自由组合,也是很灵活的。

    所以可以看到,我们定义了3个Policy,再把它们Wrap起来。

    另外,还在触发每一个Policy的时候,都会输出相应的日记,方便我们后面看效果。

    对于写日记这一块,个人认为对比Steeltoe,Polly的方式要更加方便和简单。

    下面是控制器的使用。

    // GET api/values
    [HttpGet]
    public async Task<string> A([FromServices]IAService aService)
    {
        return await aService.GetAsync();
    }
    

    还有一个关键的步骤:在Startup注册我们的AService。

    services.AddSingleton<IAService, AService>();
    

    切记是Singleton!不然熔断就不会起作用了!!

    直接上效果图

    简单说明一下这张图,一开始,服务A和调用方都是正常的,后面中断服务A,使其不可用,这个时候调用方就会走降级处理。

    调用方多请求几次,就可以看到OnBreak的日记输出,说明断路器已经处于Open状态,不会直接走真正的请求,而是走的Fallback。

    最后启动服务A,可以看到OnReset的日记输出,说明断路器已经处于Closed状态了,浏览器显示的也是服务A的返回结果。

    再来模拟一下超时的情形。

    因为上面设置的超时时间是1秒,所以让其休息1001毫秒就可以模拟了。

    // GET api/values
    [HttpGet]
    public string Get()
    {
        System.Threading.Thread.Sleep(1001);
        return "service--a";
    }
    

    再来看看效果图

    调用方一直是提示因为超时而降级,而熔断。从日记也可以看出,是因为超时而导致熔断的。

    前面还提到一个注册服务的问题,这里解释一下为什么我们要让其注册成Singleton?

    我们先把注册服务这一块调整为不是Singleton,这里以Scope为例,Transient也是一样的。

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddScoped<IAService, AService>();
        //services.AddSingleton<IAService, AService>();
        services.AddMvc();
    }
    

    效果如下:

    可以看到,日记一直输出超时!并没有提示熔断相关的信息!这说明我们设置的熔断并没有起作用!!

    这个问题与实例的生命周期有着密不可分的关系!

    试想一下,如果每次请求,都创建一个AService的实例,同样的每次都会重新创建一个新的熔断器,那熔断还会生效吗?

    反之,如果熔断器只有一个,那么无论发起多少次请求,它都是唯一的,所以它才能统计到有多少次异常,从而去触发熔断。

    这也是一个我们需要特别注意的地方。不然一个不小心就入坑了。

    总结

    Polly用起来还是比较简单,比较灵活的,我们可以组合多种不同的Policy来达到我们想要的结果。

    本文的示例代码:

    CircuitBreakerDemo

  • 相关阅读:
    (转)社会青年应如何自学英语?
    WEB标准学习路程之"CSS":13.声明,单位
    8大致命生活毛病(转)
    VS2008小Bug??
    【细嚼慢咽大数据】第一章——数据挖掘基本概念,邦弗朗尼原理,IF.IDF指标,哈希函数
    【Linux操作系统分析】定时测量——RTC,TSC,PIT,jiffies,计时体系结构,延迟函数
    【Git】Git上传本地项目的命令以及nonfastforward updates were rejected的解决办法
    【Linux操作系统分析】Ubuntu12.04内核升级和添加系统调用
    【折腾ubuntu】Ubuntu12.04安装windows版本的福昕阅读器
    【二】zTree checkbox
  • 原文地址:https://www.cnblogs.com/catcher1994/p/9032531.html
Copyright © 2011-2022 走看看