加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

再探Circuit Breaker之使用Polly

发布时间:2020-12-15 21:18:24 所属栏目:asp.Net 来源:网络整理
导读:h2 id="前言"前言 介绍了使用Steeltoe来处理服务熔断,这篇我们将用来处理服务熔断。 不废话了,直接进正题。 同样先定义一个简单的服务。 [Route("api/[controller]")]public class ValuesController : Controller{ // GET api/values [HttpGet] public str

<h2 id="前言">前言

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

不废话了,直接进正题。

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

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

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

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

public interface IAService
{
    Task GetAsync();
}

public class AService : IAService
{
private PolicyWrap _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 A([FromServices]IAService aService)
{
    return await aService.GetAsync();
}

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

services.AddSingleton();

切记是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();
    //services.AddSingleton();
    services.AddMvc();
}

效果如下:

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

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

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

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

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

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

本文的示例代码:

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读