zoukankan      html  css  js  c++  java
  • .NET Core 微服务之Polly重试策略

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

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

    允许我们以非常顺畅和线程安全的方式来执行诸如重试、断路器、超时、隔离、缓存、后退等策略, 能为我们在微服务架构提供更稳定的服务。当然,目前的 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 当前执行上下文信息。

    测试一下:

    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的相关文档看看。

    参考链接

    没有彩蛋

  • 相关阅读:
    Powerdesigner中如何生成测试数据
    iBatis #和$的区别 把int作为参数时,转换为字符型
    config或者xml中的embedded使用方法。
    C#中发送邮件
    ASP.NET中JSON的序列化和反序列化
    AspNetPager.dll 实现分页
    oracle创建表空间
    如何进行数据库,比如ORACLE,SQL SERVER的逆向工程,将数据库导入到PD中
    DataTable转换成JSON字符串的函数
    iBatis把一个表的sqlmap配置的多个xml中。
  • 原文地址:https://www.cnblogs.com/DanielYao/p/11086574.html
Copyright © 2011-2022 走看看