donet 微服务开发 学习-熔断降级 Polly

6 篇文章 0 订阅
6 篇文章 0 订阅

目的介绍

donet 微服务开发 学习

什么是熔断降级

 熔断器如同电力过载保护器。它可以实现快速失败,如果它在一段时间内侦测到许多类似的错误,会强迫其以后的多个调用快速失败,不再访问远程服务器,从而防止应用程序不断地尝试执行可能会失败的操作,使得应用程序继续执行而不用等待修正错误,或者浪费时间去等到长时间的超时产生。

降级的目的是当某个服务提供者发生故障的时候,向调用方返回一个错误响应或者替代响应。举例子:如视频播放器请求playsafe的替代方案;加载内容评论时如果出错,则以缓存中加载或者显示"评论暂时不可用" 。

Polly简介

.Net Core中有一个被.Net基金会认可的库Polly,可以用来简化熔断降级的处理。主要功能:重试(Retry) ;断路器(Circuit-breaker) ;超时检测(Timeout) ;缓存(Cache) ;,失败处理(FallBack) ;

官网: https://github. com/App-vNext/Polly

介绍文章: https://www.cnblogs.com/CreateMyself/p/7589397.html

Polly简单使用

使用Policv的静态方法创建ISyncPolicy实现类对象,创建方法既有同步方法也有异步方法,根 据自己的需要选择。下面演示同步的,异步的用法类似。

举例:当发生ArgumentException异常的时候,执行Fallback代码。

新建pollytest1控制台项目,添加nuget引用

	try
	{
	    ISyncPolicy policy = Policy.Handle<ArgumentException>(ex => ex.Message == "年龄参数错误")
	        .Fallback(() =>
	        {
	            Console.WriteLine("出错了");
	        });
	    policy.Execute(()=>{
	        //这里是可能会产生问题的业务系统代码
	        Console.WriteLine("开始任务");
	        throw new ArgumentException("年龄参数错误");
	        //throw new Exception("haha");
	        //Console.WriteLine("完成任务");
	    });
	}
	catch (Exception ex)
	{
	    Console.WriteLine($"未处理异常:{ex}");
	}

如果没有被Handle处理的异常,则会导致未处理异常被抛出。

详解Polly异常处理

. Handle<Exception> (ex->ex. Message. Contains ("aa"))

参数委托的返回值是boolean类型,如果返回true,就是“这个异常能被我处理”,否则就是“我处理不了" ,会导致未处理异常被抛出。

比如可以实现“我能处理XXX错误信息"

Handle<WebException> (ex=>ex. Status==WebExceptionStatus. SendFailure)

获取异常信息就调用这个重载

public static FallbackPolicy Fallback(this PolicyBuilder policyBuilder, Action fallbackAction, Action<Exception> onFallback);

//省略
.Fallback(() =>{},(ex)=> {
    Console.WriteLine("执行出错,异常"+ex);
});

异常处理的套路

ISyncPolicy policy = Policy.Handle<AException>()
.Or<BException>()
.Or<CException>()
......
.
CircuitBreaker()/.Fallback()/.Retry()/.RetryForever()/.WaitAndRetry()/.WaitAndRetryForever()

当发生AException或者BException或者…的时候进行CircuitBreaker()/.Fallback()等处理。

这些处理不能简单的链式调用,要用到后面的Wrap。

例如下面这样是不行的

ISyncPolicy policy = Policy
  .Handle<Exception>()
  .Retry(3)
  .Fallback(()=> { Console.WriteLine("执行出错"); });//这样不行

policy.Execute(() => {
  Console.WriteLine("开始任务");
  throw new ArgumentException("Hello world!");
  Console.WriteLine("完成任务");
});

重试处理

try
{
    ISyncPolicy policy = Policy.Handle<Exception>()
        .RetryForever();//一直重试
    policy.Execute(() =>
    {
        Console.WriteLine("开始任务");
        if (DateTime.Now.Second % 10 != 0)
        {
            throw new Exception("出错");
        }

        Console.WriteLine("完成任务");
    });
}
catch (Exception ex)
{
    Console.WriteLine($"未处理异常:{ex}");
}


//RetryForever()是一直重试直到成功
//Retry()是重试最多一次;
//Retry(n)是重试最多n次;
//WaitAndRetry()可以实现“如果出错等待100ms再试还不行再等150ms秒。。。。”,重载方法很多,一看就懂,不再一一介绍。还有WaitAndRetryForever。

短路保护Circuit Breaker

出现N次连续错误,则把“熔断器”(保险丝)熔断,等待一段时间,等待这段时间内如果再Execute则直接抛出BrokenCircuitException异常。等待时间过去之后,再执行Execute的时候如果又错了(一次就够了),那么继续熔断一段时间,否则就回复正常。

这样就避免一个服务已经不可用了,还是使劲的请求给系统造成更大压力。

ISyncPolicy policy = Policy.Handle<Exception>()
    .CircuitBreaker(6, TimeSpan.FromSeconds(5));//连续出错6次之后熔断5秒(不会再去尝试执行业务代码)。
while (true)
{
    Console.WriteLine("开始Execute");
    try
    {
        policy.Execute(() =>
        {
            Console.WriteLine("开始任务");
            throw new Exception("出错");
            Console.WriteLine("完成任务");
        });
    }
    catch (Exception ex)
    {
        Console.WriteLine("execute出错" + ex.GetType() + ":" + ex.Message);
    }
    Thread.Sleep(500);
}

在这里插入图片描述

策略封装

可以把多个ISyncPolicy合并到一起执行:

policy3= policy1.Wrap(policy2);

执行policy3就会把policy1、policy2封装到一起执行

policy9=Policy.Wrap(policy1, policy2, policy3, policy4, policy5);把更多一起封装。

超时处理

创建一个3秒钟(注意单位)的超时策略。

ISyncPolicy policy = Policy.Timeout(3, TimeoutStrategy.Pessimistic);

创建一个3秒钟(注意单位)的超时策略。超时策略一般不能直接用,而是和其他封装到一起用:

ISyncPolicy policy = Policy.Handle<Exception>()
    .Fallback(() =>
    {
        Console.WriteLine("执行出错");
    });
policy = policy.Wrap(Policy.Timeout(2, TimeoutStrategy.Pessimistic));

policy.Execute(() =>
{
    Console.WriteLine("开始任务");
    Thread.Sleep(5000);
    Console.WriteLine("完成任务");
});

在这里插入图片描述
上面的代码就是如果执行超过2秒钟,则直接Fallback,Execute中的代码也会被强行终止(引发TimeoutRejectedException异常)。

这个的用途:请求网络接口,避免接口长期没有响应造成系统卡死。

TimeoutStrategy.Optimistic是主动通知代码,告诉他“到期了”,由代码自己决定是不是继续执行,局限性很大,一般不用。

下面的代码,如果发生超时,重试最多3次(也就是说一共执行4次哦)。

ISyncPolicy policy = Policy.Handle<TimeoutRejectedException>()
    .Retry(1);
policy = policy.Wrap(Policy.Timeout(3, TimeoutStrategy.Pessimistic));
policy.Execute(() =>
{
    Console.WriteLine("开始任务");
    Thread.Sleep(5000);
    Console.WriteLine("完成任务");
});

缓存

缓存的意思就是N秒内只调用一次方法,其他的调用都返回缓存的数据。

目前只支持Polly 5.9.0,不支持最新版

Install-Package Polly.Caching.MemoryCache

功能局限性也大,简单讲一下,后续先不用这个实现缓存原则:别人的好用我就拿来用,不好用我就自己造。

命令空间都写到代码中,因为有容易引起混淆的同名类。

//Install-Package Microsoft.Extensions.Caching.Memory
Microsoft.Extensions.Caching.Memory.IMemoryCache memoryCache = new Microsoft.Extensions.Caching.Memory.MemoryCache(new Microsoft.Extensions.Caching.Memory.MemoryCacheOptions());
//Install-Package Polly.Caching.MemoryCache
Polly.Caching.MemoryCache.MemoryCacheProvider memoryCacheProvider = new Polly.Caching.MemoryCache.MemoryCacheProvider(memoryCache);

CachePolicy policy = Policy.Cache(memoryCacheProvider, TimeSpan.FromSeconds(5));
Random rand = new Random();
while (true)
{
    int i = rand.Next(5);
    Console.WriteLine("产生"+i);
    var context = new Context("doublecache" + i);
    int result = policy.Execute(ctx =>
    {
        Console.WriteLine("Execute计算"+i);
        return i * 2;
    },context);
    Console.WriteLine("计算结果:"+result);
    Thread.Sleep(500);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值