开源服务容错处理库Polly使用文档

在进入SOA之后,我们的代码从本地方法调用变成了跨机器的通信。任何一个新技术的引入都会为我们解决特定的问题,都会带来一些新的问题。比如网络故障、依赖服务崩溃、超时、服务器内存与CPU等其它问题。正是因为这些问题无法避免,所以我们在进行系统设计、特别是进行分布式系统设计的时候以“Design For Failure”(为失败而设计)为指导原则。把一些边缘场景以及服务之间的调用发生的异常和超时当成一定会发生的情况来预先进行处理。

Design For Failure
1. 一个依赖服务的故障不会严重破坏用户的体验。
2. 系统能自动或半自动处理故障,具备自我恢复能力。

以下是一些经验的服务容错模式

  • 超时与重试(Timeout and Retry)

  • 限流(Rate Limiting)

  • 熔断器(Circuit Breaker)

  • 舱壁隔离(Bulkhead Isolation)

  • 回退(Fallback)

如果想详细了解这几种模式可以参考美团技术团队的总结:服务容错模式。我们今天要讲的是,thanks to the community 多谢社区, Polly已经为我们实现了以上全部的功能。Polly是一个C#实现的弹性瞬时错误处理库(resilience and transient-fault-handling library一直觉得这个英文翻译不是很好) 。在Polly中,对这些服务容错模式分为两类:

  • 错误处理fault handling :重试、熔断、回退

  • 弹性应变resilience:超时、舱壁、缓存

可以说错误处理是当错误已经发生时,防止由于该错误对整个系统造成更坏的影响而设置。而弹性应变,则在是错误发生前,针对有可能发生错误的地方进行预先处理,从而达到保护整个系统的目地。

Polly 错误处理使用三步曲

  • 定义条件: 定义你要处理的 错误异常/返回结果

  • 定义处理方式 : 重试,熔断,回退

  • 执行

先看一个简单的例子

// 这个例子展示了当DoSomething方法执行的时候如果遇到SomeExceptionType的异常则会进行重试调用。var policy = Policy.Handle<SomeExceptionType>()   // 定义条件 .Retry(); // 定义处理方式// 执行policy.Execute(() => DoSomething());

定义条件

我们可以针对两种情况来定义条件:错误异常和返回结果。

// 单个异常类型Policy.Handle<HttpRequestException>()// 限定条件的单个异常Policy.Handle<SqlException>(ex => ex.Number == 1205)// 多个异常类型Policy.Handle<HttpRequestException>().Or<OperationCanceledException>()// 限定条件的多个异常Policy.Handle<SqlException>(ex => ex.Number == 1205).Or<ArgumentException>(ex => ex.ParamName == "example")// Inner Exception 异常里面的异常类型 Policy.HandleInner<HttpRequestException>().OrInner<OperationCanceledException>(ex => ex.CancellationToken != myToken)

以及用返回结果来限定

// 返回结果加限定条件 Policy.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.NotFound)// 处理多个返回结果Policy.HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.InternalServerError).OrResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.BadGateway)// 处理元类型结果 (用.Equals)Policy.HandleResult<HttpStatusCode>(HttpStatusCode.InternalServerError).OrResult<HttpStatusCode>(HttpStatusCode.BadGateway) 
// 在一个policy里面同时处理异常和返回结果。HttpStatusCode[] httpStatusCodesWorthRetrying = {HttpStatusCode.RequestTimeout, // 408HttpStatusCode.InternalServerError, // 500HttpStatusCode.BadGateway, // 502HttpStatusCode.ServiceUnavailable, // 503HttpStatusCode.GatewayTimeout // 504}; HttpResponseMessage result = Policy.Handle<HttpRequestException>().OrResult<HttpResponseMessage>(r => httpStatusCodesWorthRetrying.Contains(r.StatusCode)).RetryAsync(...).ExecuteAsync( /* some Func<Task<HttpResponseMessage>> */ )

定义处理方式

在这里使用的处理方式就是我们最开始说的服务容错模式,我们将介绍以下三种:重试、熔断、回退。

重试

重试很好理解,当发生某种错误或者返回某种结果的时候进行重试。Polly里面提供了以下几种重试机制

  • 按次数重试

  • 不断重试(直到成功)

  • 等待之后按次数重试

  • 等待之后不断重试(直到成功)

按次数重试

// 重试1次Policy.Handle<SomeExceptionType>().Retry()// 重试3(N)次Policy.Handle<SomeExceptionType>().Retry(3)// 重试多次,加上重试时的action参数Policy.Handle<SomeExceptionType>().Retry(3, (exception, retryCount) =>{        // 干点什么,比如记个日志之类的 });

不断重试

// 不断重试,直到成功Policy.Handle<SomeExceptionType>().RetryForever()// 不断重试,带action参数在每次重试的时候执行Policy.Handle<SomeExceptionType>().RetryForever(exception =>{        // do something });

等待之后重试

// 重试3次,分别等待1、2、3秒。Policy.Handle<SomeExceptionType>().WaitAndRetry(new[]{TimeSpan.FromSeconds(1),TimeSpan.FromSeconds(2),TimeSpan.FromSeconds(3)});

当然也可以在每次重试的时候添加一些处理,这里我们可以从上下文中获取一些数据,这些数据在policy启动执行的时候可以传进来。

Policy.Handle<SomeExceptionType>().WaitAndRetry(new[]{TimeSpan.FromSeconds(1),TimeSpan.FromSeconds(2),TimeSpan.FromSeconds(3)}, (exception, timeSpan, context) => {    // do something    });

把WiatAndRetry抱成WaitAndRetryForever()则可以实现重试直到成功。

熔断

熔断也可以被作为当遇到某种错误场景下的一个操作。以下代码展示了当发生2次SomeExceptionType的异常的时候则会熔断1分钟,该操作后续如果继续尝试执行则会直接返回错误 。

Policy.Handle<SomeExceptionType>()   .CircuitBreaker(2, TimeSpan.FromMinutes(1));

可以在熔断和恢复的时候定义委托来做一些额外的处理。onBreak会在被熔断时执行,而onReset则会在恢复时执行。

Action<Exception, TimeSpan> onBreak = (exception, timespan) => { ... };
Action onReset = () => { ... };
CircuitBreakerPolicy breaker = Policy.Handle<SomeExceptionType>().CircuitBreaker(2, TimeSpan.FromMinutes(1), onBreak, onReset);

熔断器状态

我们的CircuitBreakPolicy的State定义了当前熔断器的状态,我们也可能调用它的Isolate和Reset方法来手动熔断和恢复 。

CircuitState state = breaker.CircuitState;
  • Closed 关闭状态,允许执行

  • Open 自动打开,执行会被阻断

  • Isolate 手动打开,执行会被阻断

  • HalfOpen  从自动打开状态恢复中,在熔断时间到了之后从Open状态切换到Closed

// 手动打开熔断器,阻止执行breaker.Isolate(); // 恢复操作,启动执行 breaker.Reset();

回退(Fallback)

// 如果执行失败则返回UserAvatar.BlankPolicy.Handle<Whatever>().Fallback<UserAvatar>(UserAvatar.Blank)// 发起另外一个请求去获取值Policy.Handle<Whatever>().Fallback<UserAvatar>(() => UserAvatar.GetRandomAvatar()) // where: public UserAvatar GetRandomAvatar() { ... }// 返回一个指定的值,添加额外的处理操作。onFallbackPolicy.Handle<Whatever>().Fallback<UserAvatar>(UserAvatar.Blank, onFallback: (exception, context) => {        // do something});

执行polly policy

为我声明了一个Policy,并定义了它的异常条件和处理方式,那么接下来就是执行它。执行是把我们具体要运行的代码放到Policy里面。

// 执行一个Actionvar policy = Policy.Handle<SomeExceptionType>().Retry();policy.Execute(() => DoSomething());

这就是我们最开始的例子,还记得我们在异常处理的时候有一个context上下文吗?我们可以在执行的时候带一些参数进去

// 看我们在retry重试时被调用的一个委托,它可以从context中拿到我们在execute的时候传进来的参数 。var policy = Policy.Handle<SomeExceptionType>().Retry(3, (exception, retryCount, context) =>{        var methodThatRaisedException = context["methodName"];Log(exception, methodThatRaisedException);});policy.Execute(() => DoSomething(),	new Dictionary<string, object>() {{ "methodName", "some method" }}
);

当然,我们也可以将Handle,Retry, Execute 这三个阶段都串起来写。

Policy.Handle<SqlException>(ex => ex.Number == 1205).Or<ArgumentException>(ex => ex.ParamName == "example").Retry().Execute(() => DoSomething());

Polly 弹性应变处理Resilience

我们在上面讲了Polly在错误处理方面的使用,接下来我们介绍Polly在弹性应变这块的三个应用: 超时、舱壁和缓存。

超时

Policy.Timeout(TimeSpan.FromMilliseconds(2500))

支持传入action回调

Policy.Timeout(30, onTimeout: (context, timespan, task) => {        // do something });

超时分为乐观超时与悲观超时,乐观超时依赖于CancellationToken ,它假设我们的具体执行的任务都支持CancellationToken。那么在进行timeout的时候,它会通知执行线程取消并终止执行线程,避免额外的开销。下面的乐观超时的具体用法 。

// 声明 PolicyPolicy timeoutPolicy = Policy.TimeoutAsync(30);
HttpResponseMessage httpResponse = await timeoutPolicy.ExecuteAsync(     async ct => await httpClient.GetAsync(endpoint, ct), CancellationToken.None 
// 最后可以把外部的 CacellationToken附加到 timeoutPollcy的 CT上,在这里我们没有附加);

悲观超时与乐观超时的区别在于,如果执行的代码不支持取消CancellationToken,它还会继续执行,这会是一个比较大的开销。

Policy.Timeout(30, TimeoutStrategy.Pessimistic)

上面的代码也有悲观sad…的写法

Policy timeoutPolicy = Policy.TimeoutAsync(30, TimeoutStrategy.Pessimistic);var response = await timeoutPolicy.ExecuteAsync(    async () => await FooNotHonoringCancellationAsync(), );// 在这里我们没有 任何与CancllationToken相关的处理

舱壁

在开头的那篇文章中详细解释了舱壁这种模式,它用来限制某一个操作的最大并发执行数量 。比如限制为12

Policy.Bulkhead(12)

同时,我们还可以控制一个等待处理的队列长度

Policy.Bulkhead(12, 2)

以及当请求执行操作被拒绝的时候,执行回调

Policy.Bulkhead(12, context => {        // do something });

缓存

Polly的缓存需要依赖于一个外部的Provider。

var memoryCacheProvider = new Polly.Caching.MemoryCache.MemoryCacheProvider(MemoryCache.Default);
var cachePolicy = Policy.Cache(memoryCacheProvider, TimeSpan.FromMinutes(5));// 设置一个绝对的过期时间
var cachePolicy = Policy.Cache(memoryCacheProvider, new AbsoluteTtl(DateTimeOffset.Now.Date.AddDays(1));// 设置一个滑动的过期时间,即每次使用缓存的时候,过期时间会更新

var cachePolicy = Policy.Cache(memoryCacheProvider, new SlidingTtl(TimeSpan.FromMinutes(5));// 我们用Policy的缓存机制来实现从缓存中读取一个值,如果该值在缓存中不存在则从提供的函数中取出这个值放到缓存中。// 借且于Polly Cache 这个操作只需要一行代码即可。

TResult result = cachePolicy.Execute(() => getFoo(), new Context("FooKey")); // "FooKey" is the cache key used in this execution.// Define a cache Policy, and catch any cache provider errors for logging.var cachePolicy = Policy.Cache(myCacheProvider, TimeSpan.FromMinutes(5), (context, key, ex) => { logger.Error($"Cache provider, for key {key}, threw exception: {ex}."); // (for example) } );

组合Policy

最后我们要说的是如何将多个policy组合起来。大致的操作是定义多个policy,然后用Wrap方法即可。

var policyWrap = Policy.Wrap(fallback, cache, retry, breaker, timeout, bulkhead);
policyWrap.Execute(...)

在另一个Policy声明时组合使用其它外部声明的Policy。

PolicyWrap commonResilience = Policy.Wrap(retry, breaker, timeout);Avatar avatar = Policy.Handle<Whatever>().Fallback<Avatar>(Avatar.Blank).Wrap(commonResilience).Execute(() => { /* get avatar */ });

相关文章:

原文地址:http://www.jessetalk.cn/2018/03/25/asp-vnext-polly-docs/


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/321846.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

P2638-安全系统【数论,组合数学】

正题 题目链接:https://www.luogu.org/problem/P2638 题目大意 aaa个不同的000&#xff0c;bbb个不同的111。nnn个位置每个可以放0,10,10,1可以都放也可以不放也可以只放一个。然后求方案数。 解题思路 答案就是(∑i0aCni∗Cai)∗(∑i0bCni∗Cbi)(\sum_{i0}^a C_{n}^{i}*C_{a…

宝石排列问题

西安交大 软件53 蔡少斐 题号&#xff1a;5_10 题目叙述&#xff1a; 现有n种不同形状的宝石&#xff0c;每种n颗&#xff0c;共n*n颗。同一形状的n颗宝石分别具有n种不同的颜色c1,c2,…,cn中的一种颜色。欲将这n*n颗宝石排列成n行n列的一个方阵&#xff0c;使方阵中每一行…

大部分Intel hardware intrinsic 将在 .NET Core 2.1 中启用

编者注&#xff1a;SIMD via C# 引入了一套全新的机制&#xff0c;使得C# 以后可以像C/C 一样直接使用intrinsic functions 来直接操作Intel CPU 的大多数SIMD 指令了&#xff08;从SSE 到AVX2&#xff09;随着 .NET Core 2.1 发布的临近&#xff0c;上周CoreCLR 已经停止向mas…

运动员最佳配对问题

西安交大 软件53 蔡少斐 题号&#xff1a;6_5 题目叙述&#xff1a; 羽毛球队有男女运动员各n人。 给定2个nn矩阵P和Q。P[i][j]是男运动员i和女运动员j配对组成混合双打的男运动员竞赛优势&#xff1b;Q[i][j]是女运动员i和男运动员j配合的女运动员竞赛优势。 由于技术配合…

P2217-[HAOI2007]分割矩阵【dfs,记忆化搜索】

正题 题目链接:https://www.luogu.org/problem/P2217 题目大意 a∗ba*ba∗b的矩阵&#xff0c;分成nnn个矩阵&#xff0c;求每个矩阵均方差最小&#xff0c;求答案。 解题思路 切n−1n-1n−1刀 设fk,x1,y1,x2,y2f_{k,x1,y1,x2,y2}fk,x1,y1,x2,y2​表示矩阵(x1,y1,x2,y2)(x1,y…

play框架入门操作

Play的基本特性&#xff1a;1、Play框架使用REST的开发风格&#xff0c;不用严格按照复杂的J2EE规范&#xff0c;是Java敏捷开发的首选。2、Play框架提供多种支持&#xff1a;NIO&#xff0c;JPA&#xff0c;Groovy以及各种工具类。3、Play框架会自动编译Java源文件&#xff0c…

动态规划练习1 [导弹拦截]

【问题描述】 某国为了防御敌国的导弹袭击&#xff0c;发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷&#xff1a;虽然 它的第一发炮弹能够到达任意的高度&#xff0c;但是以后每一发炮弹都不能高于前一发的高度。某天&#xff0c;雷达捕捉到 敌国的导弹来袭。由于该…

TensorflowSharp 简单使用与KNN识别MNIST流程

机器学习是时下非常流行的话题&#xff0c;而Tensorflow是机器学习中最有名的工具包。TensorflowSharp是Tensorflow的C#语言表述。本文会对TensorflowSharp的使用进行一个简单的介绍。本文会先介绍Tensorflow的一些基本概念&#xff0c;然后实现一些基本操作例如数字相加等运算…

1、jquery事件绑定和委托的实现

jQuery的事件绑定和委托可以使用 on()、one()、bind()、live()、delegate()等方法实现。 1、on() &#xff1a; 语法&#xff1a;$(selector).on(event,childSelector,data,function) 作用&#xff1a;可以在被选元素及子元素上添加一个或多个事件处理程序&#xff0c;并且…

刷题bingo挑战赛1

前言 为了提高做题效率&#xff0c;最近发现了个玩bingo的好网站 https://bingosync.com 然后就有了这场bingobingobingo赛。 正题 生成代码 [ {"name":"P2638"},{"name":"P4265"},{"name":"P2331"},{"n…

动态规划练习2 [合唱队形]

N 位同学站成一排&#xff0c;音乐老师要请其中的 (N-K) 位同学出列&#xff0c;使得剩下的 K 位同学排成合唱队形。 合唱队形是指这样的一种队形&#xff1a;设 K 位同学从左到右依次编号为 1 &#xff0c; 2 …&#xff0c; K &#xff0c;他们的身高分别为 T1 &#x…

ASP.NET Core Web 支付功能接入 微信-扫码支付篇

这篇文章将介绍ASP.NET Core中使用 开源项目 Payment&#xff0c;实现接入微信-扫码支付及异步通知功能。开发环境&#xff1a;Win 10 x64、VS2017 15.6.4、.NET Core SDK 2.1.101、.NET Core Runtime 2.0.61.新建"ASP.NET Core Web 应用程序"项目&#xff0c;我将它…

jzoj3832-在哪里建酿酒厂【指针】

正题 题目链接:https://jzoj.net/senior/#main/show/3832 题目大意 一个环形的&#xff0c;知道每个城市分布的位置和需要的酒数。然后要求在一个位置建厂使得运输价格最低。 解题思路 我们将数据复制一份放到后面&#xff0c;然后枚举建厂位置。我们现在要找到一个包含该位…

14、java中的集合(1)

1、为什么使用集合 面向对象语言使用对象体现事物&#xff0c;存储对象可以使用数组&#xff0c;但是数组的长度是固定的&#xff0c;存储的对象类型单一&#xff0c;不适用需求的变化&#xff0c;所以提供了集合。 2、集合和数组的区别 1&#xff09;数组长度定义之后不能改…

动态规划练习3 [砝码称重]

【问题描述】 设有 1g 、 2g 、 3g 、 5g 、 10g 、 20g 的砝码各若干枚&#xff08;其总重 <1000 &#xff09;&#xff0c;用他们能称出的重量的种类数。 【输入文件】 a1 a2 a3 a4 a5 a6 &#xff08;表示 1g 砝码有 a1 个&#xff0c; 2g 砝码有 a2 个…

Microsoft AI - Custom Vision in C#

概述前面一篇 Microsoft AI - Custom Vision 中&#xff0c;我们介绍了 Azure 认知服务中的自定义影像服务&#xff1a;Custom Vision&#xff0c;也介绍了如果通过这个在线服务&#xff0c;可视化的完成项目创建、数据集上传和标注、模型训练、模型评估和测试。我们也提到&…

jzoj3833-平坦的折线【模型转换,LIS】

正题 题目链接:https://jzoj.net/senior/#contest/show/2930/3 题目大意 一个平面直角坐标系上有nnn个点&#xff0c;如果两个点之间斜率在−1∼1-1\sim 1−1∼1之间那么就可以连接&#xff0c;求最少多少条折线可以连接这些点。 解题思路 我们将整个坐标系逆时针选择45∘(4…

22、mysql主键自增值和偏移量的查看和修改

1、查看mysql自增值和偏移量 show variables like %increment%; auto_increment_increment1 -- 自增倍数是1 auto_increment_offset1 -- 偏移量是1 上边这是一般的设置&#xff0c;每次每次主键自增的倍数是1&#xff0c;偏移量是1 例如&#xff1a;插入第n条记录&#x…

动态规划训练5 [回文词]

【问题描述】 回文词是一种对称的字符串——也就是说&#xff0c;一个回文词&#xff0c;从左到右读和从右到左读得到的结果是一样 的。任意给定一个字符串&#xff0c;通过插入若干字符&#xff0c;都可以变成一个回文词。你的任务是写一个程序&#xff0c;求出将 给定字符串变…

Unity引擎及编辑器C#源代码发布

3月23日我们在GitHub上发布了Unity引擎和编辑器的C#源代码&#xff0c;仅供Unity学习参考使用。为何如此决定为了了解或改进自己的Unity项目&#xff0c;一直以来有用户对Unity .NET程序集反汇编&#xff0c;我们的服务条款明确允许这样做。但反汇编有二大缺点&#xff1a;尽管…