Polly 是 .Net 下的一套瞬时故障处理及恢复的函式库,可让开发者以fluent及线程安全的方式来应用诸如RetryCircuit BreakerTimeoutBulkhead IsolationFallback等策略。

安装

可以通过Nuget实现快速安装: Install-Package Polly

基本用法

一个简单的示例如下:

var policy = Policy
    .Handle<DivideByZeroException>()    //定义所处理的故障
    .Retry();    //故障的处理方法

policy.Execute(() => DoSomething());    //应用策略

从上面的例子中我们可以看出,使用该策略一般包括三个步骤:

  1. 定义所处理的故障
  2. 定义故障的处理方法
  3. 应用策略

上述代码在功能上和下面的代码等价:

for (int i = 0; i < 2; i++)
{
    try
    {
        DoSomething();
    }
    catch (DivideByZeroException)
    {
        if (i > 1)
            throw;
    }
}

虽然这个例子比较简单,带来的优越性并不明显,但它以一种比较规范的方式定义了异常的处理策略,一来带来了更好的体验,带来了更好的代码可读性,另外,随着异常策略的复杂,它所带来的对代码的简化就更加明显了。下面就稍微详细一点的深入介绍一下:

 

定义错误(故障)

常见故障定义方式是指定委托执行过程中出现的特定异常,Polly中支持异常处理方式如下:

// 处理指定异常
Policy.Handle<DivideByZeroException>();

// 处理有条件的指定异常
Policy.Handle<SqlException>(ex => ex.Number == 1205);

// 处理多种异常
Policy.Handle<DivideByZeroException>()
    .Or<ArgumentException>();

// 处理多种有条件的异常
Policy.Handle<SqlException>(ex => ex.Number == 1205)
    .Or<ArgumentException>(ex => ex.ParamName == "example");

也支持异常的聚合:

Policy.Handle<ArgumentException>()
    .Or<ArgumentException>();

另外,也支持通过返回值判断是否故障:

// 指定错误的返回值
Policy.HandleResult<int>(ret => ret <= 0);

 

故障处理策略:重试

常见的处理策略是重试,Polly库中内置了各种常用的重试策略:


Policy.Handle<TimeoutException>().Retry();

// 重试多次
Policy.Handle<TimeoutException>().Retry(3);

// 无限重试
Policy.Handle<TimeoutException>().RetryForever();

也支持retry时增加一些额外的行为:

Policy.Handle<TimeoutException>().Retry(3, (err, countdown, context) =>
{
    // log retry
});

也支持等待并重试:

// 等待并重试
Policy.Handle<TimeoutException>().WaitAndRetry(3, _ => TimeSpan.FromSeconds(3));

 

故障处理策略:回退(Fallback)

Fallback策略是在遇到故障是指定一个默认的返回值,

Policy<int>.Handle<TimeoutException>().Fallback(3);
Policy<int>.Handle<TimeoutException>().Fallback(() => 3);

当然,遇到没有返回值的也可以指定故障时的处理方法,

Policy.Handle<TimeoutException>().Fallback(() => { });

使用Fallback时,异常被捕获,返回默认的返回结果。

PS: 带参数的Fallback处理方式貌似在5.0之后发生了变化,成了本文所示的方式,以前是Fallback<T>

 

故障处理策略:断路保护(Circuit Breaker)

Circuit Breaker也是一种比较常见的处理策略,它可以指定一定时间内最大的故障发生次数,当超过了该故障次数时,在该时间段内,不再执行Policy内的委托。下面以一个简单的示例演示下该策略的功能:

static void testPolicy()
{
    var circuitBreaker = Policy.Handle<TimeoutException>()
            .CircuitBreaker(3, TimeSpan.FromMinutes(1));
    for (int i = 0; i < 5; i++)
    {
        try
        {
            circuitBreaker.Execute(DoSomething);
        }
    
        catch (Polly.CircuitBreaker.BrokenCircuitException e)
        {
            Console.WriteLine(e.Message);
        }
        catch (TimeoutException)
        {
            Console.WriteLine("timeout");
        }
    }
}

static int index = 0;
static int DoSomething()
{
    Console.WriteLine($"DoSomething {index++}");
    throw new TimeoutException();
}

执行结果如下:

DoSomething 0
timeout
DoSomething 1
timeout
DoSomething 2
timeout
The circuit is now open and is not allowing calls.
The circuit is now open and is not allowing calls.

可以看到,前面3次都能执行委托DoSomething,但出错次数到达3次后,已经进入断路保护章台,后面两次调用直接返回BrokenCircuitException。直到达到保护时间超时后,对策略的调用才会再次执行DoSomething委托。

这种策略在调用远程服务时非常实用,当一定时间内的调用都出错时,往往可以认为服务提供者已经不可用,后续调用完全可以直接失败,以避免重试的开销。直到一定时间后才需要再次重试。

相对其它处理策略,CircuitBreaker是一个比较复杂的策略,它是有状态的,可以通过CircuitState属性获取:

var state = circuitBreaker.CircuitState;

它有四种状态:

  • CircuitState.Closed - 常态,可执行actions。
  • CircuitState.Open - 自动控制器已断开电路,不允许执行actions。
  • CircuitState.HalfOpen - 在自动断路时间到时,从断开的状态复原。可执行actions,后续的action/s或控制的完成,会让状态转至Open或Closed。
  • CircuitState.Isolated - 在电路开路的状态时手动hold住,不允许执行actions。

除了超时和策略执行失败的这种自动方式外,也可以手动控制它的状态:

// 手动打开(且保持)一个断路器–例如手动隔离downstream的服务
circuitBreaker.Isolate();

// 重置一个断路器回closed的状态,可再次接受actions的执行
circuitBreaker.Reset();

更多的介绍可以参看官方文档:Circuit Breaker

 

故障封装策略(PolicyWrap)

我们可以通过PolicyWrap的方式,封装出一个更加强大的策略:

var fallback = Policy<int>.Handle<TimeoutException>().Fallback(100);
var retry = Policy<int>.Handle<TimeoutException>().Retry(2);

var retryAndFallback = fallback.Wrap(retry);

这个策略就是将Retry和Fallback组合起来,形成一个retry and fallback的策略,也可以写成如下形式:

Policy.Wrap(fallback, retry);

当执行这个新策略时:

retryAndFallback.Execute(DoSomething);

等价于执行:

fallback.Execute(()=> retry.Execute(DoSomething));

封装策略本身是属于弹性策略的范畴,这里只是提及一下,以演示Polly模块强大的功能,关于弹性策略更多内容在下文中再做更详细的介绍。

Polly简介 — 1. 故障处理策略的更多相关文章

  1. Polly简介 — 2. 弹性策略

    和故障处理策略不同的是,弹性策略并不是针对委托执行过程中的异常进行处理,而是改变委托本身的行为,因此弹性策略并没有故障定义这一过程,它的处理流程为: 定义策略 应用策略 Polly对弹性策略也做了不少 ...

  2. Polly简介 — 3. 执行策略

    执行策略 执行策略的常见方式是调用策略的Execute函数 var policy = Policy.Handle<TimeoutException>().Retry();policy.Ex ...

  3. Linux防火墙简介 – iptables配置策略

    Linux防火墙简介 – iptables配置策略 Netfilter/iptables简介 要想真正掌握Linux防火墙体系,首先要搞清楚Netfilter和iptables的关系,Netfilte ...

  4. dubbo源码阅读之集群(故障处理策略)

    dubbo集群概述 dubbo集群功能的切入点在ReferenceConfig.createProxy方法以及Protocol.refer方法中. 在ReferenceConfig.createPro ...

  5. 【微服务No.2】polly微服务故障处理库

    熔断.降级: 熔断:熔断就是我们常说的“保险丝”,意为当服务出现某些状况时,切断服务,从而防止应用程序不断地常识执行可能会失败的操作造成系统的“雪崩”,或者大量的超时等待导致系统卡死等情况,很多地方也 ...

  6. ASP.NET Core 2.1 中的 HttpClientFactory (Part 4) 整合Polly实现瞬时故障处理

    原文:https://www.stevejgordon.co.uk/httpclientfactory-using-polly-for-transient-fault-handling发表于:2018 ...

  7. NET Core微服务之路:弹性和瞬态故障处理库Polly的介绍

    前言 上一节中我们介绍了Ocelot的常见使用配置,通过json配置文件,实现API网关的请求处理.和一个使用DownStream扩展下游中间件,来实现Http转RPC的简单实现,功能不算强大,但可以 ...

  8. .NET Core 微服务之Polly熔断策略

    紧接着上一篇说,咱们继续介绍Polly这个类库 熔断策略(Circuit-breaker) 如果调用某个目标服务出现过多超时.异常等情况,可以采取一定时间内熔断该服务的调用,熔断期间的请求将不再继续调 ...

  9. 微服务之Polly熔断策略

    NET Core 微服务之Polly熔断策略 紧接着上一篇说,咱们继续介绍Polly这个类库 熔断策略(Circuit-breaker) 如果调用某个目标服务出现过多超时.异常等情况,可以采取一定时间 ...

随机推荐

  1. 栈应用之 背包问题(Python 版)

    栈应用之 背包问题 背包问题描述:一个背包里可以放入重量为weight的物品,现有n件物品的集合s,其中物品的重量为别为w0,w1,...,wn-1.问题是能否从中选出若干件物品,其重量之和正好等于w ...

  2. 缓存数据库-redis数据类型和操作(hash)

    一:Redis 哈希(Hash) Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象. Redis 中每个 hash 可以存储 232 - 1 ...

  3. luoguP2735 电网 Electric Fences

    一道校内模拟赛遇见的题 ** 不会正解就真的很麻烦的 数学题 ** 有一种东西叫 皮克定理 发现的千古神犇: 姓名:George Alexander Pick(所以叫皮克定理呀 国籍:奥地利(蛤!竟然 ...

  4. 使用JS实现文字搬运工

    使用JS实现文字搬运工 效果图: 代码如下,复制即可使用: <!DOCTYPE html> <html><head><meta http-equiv=&quo ...

  5. 使用html+css+js实现3D相册

    使用html+css+js实现3D相册,快来上传的照片吧 效果图: 代码如下,复制即可用: <!DOCTYPE html> <html lang="en"> ...

  6. plsql developer配置

    一:今天plsql developer连接 出问题了 ,Oracleclient没正确安装 0.连接vpn 1.环境变量:TNS_ADMIN = D:\worksoftware\oracleClien ...

  7. Spring cloud Feign 调用端不生效

    如果提供方的接口经过测试是没问题的话. 消费方启动类加上@EnableFeignClients 注意定义的接口如果不和启动类在同一个包路径下,需要加basePackages 即:@EnableFeig ...

  8. ROS数据可视化工具Rviz和三维物理引擎机器人仿真工具V-rep Morse Gazebo Webots USARSimRos等概述

    ROS数据可视化工具Rviz和三维物理引擎机器人仿真工具V-rep Morse Gazebo Webots USARSimRos等概述 Rviz Rviz是ROS数据可视化工具,可以将类似字符串文本等 ...

  9. MEF实现设计上的“松耦合”(一)

    1.什么是MEF 先来看msdn上面的解释:MEF(Managed Extensibility Framework)是一个用于创建可扩展的轻型应用程序的库. 应用程序开发人员可利用该库发现并使用扩展, ...

  10. 配置toad远程连接oracle

    在oracle服务器上: C:\app\Administrator\product\11.2.0\dbhome_1\NETWORK\ADMIN目录 文件:listener.ora(10.144.118 ...