Polly是一个.NET弹性和瞬时故障处理库,它允许开发人员以流畅且线程安全的方式表达策略,如失败重试、服务熔断、超时处理、舱壁隔离、缓存策略和失败降级。
Polly
Polly.Extensions.Http
在分布式的系统中,为了保障服务的高性能、高可用,我们需要做流量控制,如负载均衡、服务路由、熔断、降级、限流和流量相关调度。
自己的服务所依赖的某一个上游的底层服务挂了,当出现大量请求时,所有连接超时,Socket连接无法及时释放,导致内存溢出,出现OOM。
举例两个真实场景:
比如由于底层的权限服务挂了,导致所有业务线依赖于这个权限服务都出现不可用的情况。
最近我们组在使用Redis时,使用后未及时释放,由于连接池最大只有128,这时某同学封装的阻塞式Redis锁,不断循环去竞争锁,导致Redis服务一直处于不可用的状态。
背景:目前我们依赖一套标准的Restful风格API,通过Http请求,我们来封装一套瞬时处理的策略组件。Http的请求库我用的是RestSharp。
重试策略在Http请求中,比如网络的瞬时故障,或者对方服务由于发版上线导致的某一时刻的无法建立连接;另一种情况为,由于调用频率触发了对象服务的限频,需要我们Sleep(1s),这种小概率场景我们可以通过重试,来提高服务请求的可用性。对于标准的RestfulAPI我们会通过HttpStatus的状态码来判断异常处理重试策略。
varretryPolicy=Policy<IRestResponse>.HandleResult(restResponse=>{//http网络瞬时故障//ReSharperdisableonceConvertIfStatementToReturnStatementif(response.ResponseStatus==ResponseStatus.Error||response.ResponseStatus==ResponseStatus.TimedOut||response.StatusCode>=HttpStatusCode.InternalServerError;){returntrue;}returnfalse;}).WaitAndRetry(3,i=>TimeSpan.FromSeconds(1));returnretryPolicy;熔断、舱壁隔离策略当某个上游无服务发生宕机或不可用时,为了避免我们自己的业务服务被拖垮,我们可以采用熔断策略。如实例代码:
第一个参数:failureThreshold=0.8表示故障阈值,比如100个请求,80个失败了,就会触发断路器。
第二个参数:samplingDuration,表示根据30s内的数据样本做判断。可能某上游服务,由于网络瞬时故障5s内不可用,第6s网络恢复,如果我们设置的时间过短,立马触发断路器,而从熔断恢复正常,可能需要10s,这样设计就不太合理了。所以建议这个参数,既不要设置的太小,也不要设置的太大。
第三个参数:minimumThroughput=50,触发熔断最小的请求次数。必须大于50次。
当前的熔断策略就是,在30s内,请求大于50次,失败的请求超过80%,则会触发熔断机制。
///<summary>///熔断策略///会抛出:BrokenCircuitException///</summary>///<paramname="onBreakAction"></param>///<paramname="onResetAction"></param>///<paramname="onHalfOpenAction"></param>///<paramname="failureThreshold"></param>///<returns></returns>publicstaticCircuitBreakerPolicy<IRestResponse>CircuitBreakerPolicy(Action<DelegateResult<IRestResponse>,TimeSpan>onBreakAction,ActiononResetAction,ActiononHalfOpenAction,doublefailureThreshold=0.8){varbulkhead=Policy<IRestResponse>.HandleResult(InvalidStatus).AdvancedCircuitBreaker(failureThreshold,samplingDuration:TimeSpan.FromSeconds(30),50,TimeSpan.FromSeconds(30),onBreakAction,onResetAction,onHalfOpenAction);returnbulkhead;}降级策略当某个服务请求触发了熔断策略后,为了保障服务的可用性,我们一般会降级处理,比如零时读取缓存数据,或直接提示服务异常,及时返回异常信息。
参考polly的熔断策略,熔断后会触发BrokenCircuitException异常。我们针对这个异常做降级处理,无论是缓存还是直接异常返回,保证服务的快速响应,不会由于大量请求响应超时而宕机。
publicstaticPolicyWrap<IRestResponse>FailBackPolicy(Action<DelegateResult<IRestResponse>,TimeSpan>onBreakAction,ActiononResetAction,ActiononHalfOpenAction){//熔断后的降级策略,直接返回错误信息varfailBack=Policy<IRestResponse>.Handle<BrokenCircuitException>().Fallback(()=>newRestResponse(){ResponseStatus=ResponseStatus.Error,//需要注意,重试策略如果判断如果和该条件一致,则会导致,熔断降级后继续发生重试。StatusCode=HttpStatusCode.ExpectationFailed,ErrorMessage="当前服务接口熔断不可用,已降级。"});returnPolicy.Wrap(failBack,BulkheadPolicy(onBreakAction,onResetAction,onHalfOpenAction));}组合所有策略通过Castle或Autofac我们可以轻易的实现动态代理。以切面的形式实现控制层面的逻辑,不影响标准的业务。策略组合的顺序是很重要的,最外层的最先触发。
需要注意的是,如果服务已经触发熔断并降级后,我们需要注意降级策略的返回值和重试的前置条件,如果降级返回的Response.HttpStatusCode==500,就会继续触发重试的逻辑。导致熔断恢复周期可能会变长。
publicclassRestClientPolicyInterceptor:IInterceptor{publicRestClientPolicyInterceptor(){}///<summary>///北森RestClient代理封装///</summary>///<paramname="invocation"></param>publicvoidIntercept(IInvocationinvocation){//1.判断是否熔断,实现舱壁隔离//2.判断网络瞬时故障的重试策略。//3.Token失效的重试策略stringmethodName=invocation.Method.Name;PolicyWrap<IRestResponse>policy=Policy.Wrap(RequestExceptionRetryPolicy(),BulkheadFailBackPolicy((result,span)=>{Logger.Error($"{methodName}:触发熔断。");},()=>{Logger.Error($"{methodName}:熔断,Rest。");},()=>{Logger.Error($"{methodName}:熔断,HalfOpen。");}));policy.Execute(()=>{invocation.Proceed();returninvocation.ReturnValueasIRestResponse;});invocation.ReturnValue=restResponse;}作者:Moonus
logo设计
创造品牌价值
¥500元起
APP开发
量身定制,源码交付
¥2000元起
商标注册
一个好品牌从商标开始
¥1480元起
公司注册
注册公司全程代办
¥0元起
查
看
更
多
开源组件Polly介绍及策略详解
Polly简介Polly是一个.NET弹性和瞬时故障处理库,它允许开发人员以流畅且线程安全的方式表达策略,如失败重试、服务熔断、超时处理、舱壁隔离、缓存策略和失败降级。Polly Polly.Extensions.Http 在分布式的系统中,为了保障服务的高性能、高可用,我们需要做流量控制,如负载均衡、服务路由、熔断、降级、限流和...
开源组件:CaslteDynamicProxy
应用场景:通过代理,我们可以在客户端执行前后,做一些我们期望的行为动作。如打日志、做缓存。将控制逻辑,和业务代码分离开。比如我们在请求第三方的API,为了保障服务的高可用,我们期望引入一些策略,如重试、熔断、降级等。(Polly),我们可以借助Caslte通过切面的方式实现策略,将业务逻辑与控制逻辑分离。
前端通讯协议:WebSocket和长轮询对比分析详解
开源解决方案大多数库都不会独立于其他传输来实现长轮询,因为一般来说,长轮询通常伴随着其他传输策略,作为后备或当长轮询不起作用时将这些传输作为后备。在2018年及以后,独立的长轮询库尤其不常见,因为面对对更现代的替代方案的广泛支持,这种技术正迅速失去相关性。下面是几种不同语言的长轮询开源库...