.NET Core 微服务之Polly重试策略

接着上一篇说,正好也是最近项目里用到了,正好拿过来整理一下,园子里也有一些文章介绍比我详细。git

简单介绍一下绍轻量的故障处理库 Polly  Polly是一个.NET弹性和瞬态故障处理库github

容许咱们以很是顺畅和线程安全的方式来执行诸如重试、断路器、超时、隔离、缓存、后退等策略, 能为咱们在微服务架构提供更稳定的服务。固然,目前的 Service Mesh 显得更高大上,并且更强大,它更偏向从运维层面解决以上问题,不过这仍是的看具体项目中怎么去使用和决定了。缓存

 

在微服务架构下,咱们可能会遇到相似如下问题:安全

  1. 某些接口异常,最终形成应用程序池奔溃;
  2. 某些接口不稳定、偶尔超时,数据获取异常;
  3. 某些服务不稳定,调用方链接不上;
  4. 某些服务异常,最终主服务挂掉(雪崩效应);

 

 固然在实际状况下,咱们可能只须要确保提供给用户的服务是可用状态,不出现 “Service Unavailable” 这样的画面就好。至于接口偶尔异常,可能对某些类型的项目来讲并不太关键,用户可能经过从新请求、刷新页面就能够解决,固然咱们还能够在代码层面作兼容,满满的try/catch、for/while 循环解决重试来保证更高的可靠性。架构

 这个时候Polly就能很好的起来做用,Polly 的使用相对比较简单,固然仍是得看项目结构。咱们的主项目在调用微服务接口时使用了AOP,相似这种状况下,因此调用微服务的接口都是统一入口,因此咱们只须要在AOP内加上 Polly 的一些策略,其余代码不用作任何修改,就能够解决一些问题了。框架

安装

Install-Package Polly

使用步骤说明

  1. 定义策略
  2. 执行方法

能够看一下代码,咱们项目主要使用的是Grpc这个框架,其余的微服务框架,使用起来大体差很少
public void Intercept(IInvocation invocation)
{
    // some code 
    try
    {
        // 建立一个策略,若是 invocation.Proceed 的执行出现 Grpc.Core.RpcException 异常,而且 StatusCode == Grpc.Core.StatusCode.Unavailable,则重试一次
        var policy = Policy
        .Handle<Grpc.Core.RpcException>(t => t.Status.StatusCode == Grpc.Core.StatusCode.Unavailable)
        .Retry(); // 默认一次

        // 将策略应用到 invocation.Proceed 方法上
        policy.Execute(invocation.Proceed);
    }
    catch (Exception ex)
    {
        // some code 
        Console.WriteLine($"{ ex.Message},{ex.StackTrace}");
    }
}

 

 

策略条件定义

策略的执行须要依赖于条件,Polly 支持对异常与结果进行策略条件定义。运维

异常微服务

// 指定某个异常
Policy
  .Handle<SomeExceptionType>();

// 指定某个异常条件
Policy
  .Handle<SomeExceptionType>(ex => ex.xxx == "xxx")

// 指定多个异常
Policy
  .Handle<SomeExceptionType1>()
  .Or<SomeExceptionType2>()

// 指定多个可能异常条件
Policy
  .Handle<SomeExceptionType1>(ex => ex.xxx1 == "xxx")
  .Or<SomeExceptionType2>(ex => ex.xxx2 == "xxx")

返回结果测试

// 指定某个结果
Policy
  .HandleResult<ResponseMessage>(r => r.xxx == "xxx")

// 指定多个可能的结果
Policy
  .HandleResult<ResponseMessage>(r => r.xxx1 == "xxx")
  .OrResult<ResponseMessage>(r => r.xxx2 == "xxx")

重试策略(Retry )

// 指定异常下重试一次
Policy
  .Handle<SomeExceptionType>()
  .Retry();

// 指定异常下重试3次
Policy
  .Handle<SomeExceptionType>()
  .Retry(3);

// 指定异常下无限重试
Policy
  .Handle<SomeExceptionType>()
  .RetryForever();

// 每次重试之间等待指定的时间间隔
Policy
  .Handle<SomeExceptionType>()
  .WaitAndRetry(new[]
  {
    TimeSpan.FromSeconds(1),
    TimeSpan.FromSeconds(3),
    TimeSpan.FromSeconds(7)
  });

Retry 能够指定一个要执行的 Action。Action 参数:exception 当前异常信息,retryCount 当前执行第几回,context 当前执行上下文信息。spa

测试一下:

private static int times = 0;

public static void TestPolicy()
{
    var policy = Policy
        .Handle<Exception>()
        .Retry(3, (exception, retryCount, context) => // 出异常会执行如下代码
        {
            Console.WriteLine($"exception:{ exception.Message}, retryCount:{retryCount}, id:{context["id"]}, name:{context["name"]}");
        });

    try
    {
        // 经过 new Context 传递上下文信息
        var result = policy.Execute(Test, new Context("data", new Dictionary<string, object>() { { "id", "1" }, { "name", "beck" } }));
        Console.WriteLine($"result:{result}");
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}

private static string Test()
{
    // 每执行一次加1
    times++;

    // 前2次都抛异常
    if (times < 3)
    {
        throw new Exception("exception message");
    }
    return "success";
}

测试结果:

 

能够看到获得了我们想要的效果,具体项目能够具体去实施,下一篇我们接着说Polly熔断策略。感兴趣能够自行搜索Polly的相关文档看看。

参考连接

 

没有彩蛋

相关文章
相关标签/搜索