sentinel中的QPS降级操作DegradeSlot
sentinel通过在各种slot来实现不同的功能,其中的DegradeSlot就是根据各种规则来进降级操作,下面介绍一下DegradeSlot。
DegradeSlotentrypublicvoidentry(Contextcontext,ResourceWrapperresourceWrapper,DefaultNodenode,intcount,booleanprioritized,Object。。。args)throwsThrowable{DegradeRuleManager。checkDegrade(resourceWrapper,context,node,count);fireEntry(context,resourceWrapper,node,count,prioritized,args);}publicstaticvoidcheckDegrade(ResourceWrapperresource,Contextcontext,DefaultNodenode,intcount)throwsBlockException{SetDegradeRulerulesdegradeRules。get(resource。getName());if(rulesnull){return;}for(DegradeRulerule:rules){if(!rule。passCheck(context,node,count)){thrownewDegradeException(rule。getLimitApp(),rule);}}}
Degrade通过函数checkDegrade来实现降级操作。先通过资源名从degradeRules中获取降级规则DegradeRule的集合,然后逐个调用DegradeRule中的函数passCheck来进行校验。
DegradeRulepassCheckpublicbooleanpassCheck(Contextcontext,DefaultNodenode,intacquireCount,Object。。。args){返回false直接进行降级if(cut。get()){returnfalse;}降级是根据资源的全局节点来进行判断降级策略的ClusterNodeclusterNodeClusterBuilderSlot。getClusterNode(this。getResource());if(clusterNodenull){returntrue;}根据响应时间降级策略if(gradeRuleConstant。DEGRADEGRADERT){获取节点的平均响应时间doublertclusterNode。avgRt();if(rtthis。count){passCount。set(0);returntrue;}rtSlowRequestAmount默认是5Sentinelwilldegradetheserviceonlyifcountexceeds。if(passCount。incrementAndGet()rtSlowRequestAmount){returntrue;}根据异常比例降级}elseif(gradeRuleConstant。DEGRADEGRADEEXCEPTIONRATIO){doubleexceptionclusterNode。exceptionQps();doublesuccessclusterNode。successQps();doubletotalclusterNode。totalQps();IftotalamountislessthanminRequestAmount,therequestwillpass。if(totalminRequestAmount){returntrue;}Inthesamealignedstatistictimewindow,success(aka。completedcount)exceptioncountnonexceptioncount(realSuccess)doublerealSuccesssuccessexception;if(realSuccess0exceptionminRequestAmount){returntrue;}if(exceptionsuccesscount){returntrue;}根据异常数降级}elseif(gradeRuleConstant。DEGRADEGRADEEXCEPTIONCOUNT){doubleexceptionclusterNode。totalException();if(exceptioncount){returntrue;}}根据设置的时间窗口进行重置if(cut。compareAndSet(false,true)){ResetTaskresetTasknewResetTask(this);pool。schedule(resetTask,timeWindow,TimeUnit。SECONDS);}returnfalse;}
这个方法首先会去获取cut的值,如果是true那么就直接进行限流操作。然后会根据resource获取ClusterNode全局节点。往下分别根据三种不同的策略来进行降级。DEGRADEGRADERT根据响应时间进行降级if(gradeRuleConstant。DEGRADEGRADERT){获取节点的平均响应时间doublertclusterNode。avgRt();if(rtthis。count){passCount。set(0);returntrue;}rtSlowRequestAmount默认是5Sentinelwilldegradetheserviceonlyifcountexceeds。if(passCount。incrementAndGet()rtSlowRequestAmount){returntrue;}}
如果是根据响应时间进行降级,那么会获取clusterNode的平均响应时间,如果平均响应时间大于所设定的count(默认是毫秒),那么就调用passCount加1,如果passCount大于5,那么直接降级。
所以看到这里我们应该知道根据平均响应时间降级前几个请求即使响应过长也不会立马降级,而是要等到第六个请求到来才会进行降级。
我们进入到clusterNode的avgRt方法中看一下是如何获取到clusterNode的平均响应时间的。publicdoubleavgRt(){获取当前时间窗口内调用成功的次数longsuccessCountrollingCounterInSecond。success();if(successCount0){return0;}获取窗口内的响应时间returnrollingCounterInSecond。rt()1。0successCount;}
这个方法主要是调用rollingCounterInSecond获取成功次数,然后再获取窗口内的响应时间,用总响应时间除以次数得到平均每次成功调用的响应时间。而在时间窗口内的总相应时间和总成功次数,则是通过StatisticSlot整个slot中的滑窗功能来统计。
DEGRADEGRADERT根据响应时间进行降级if(gradeRuleConstant。DEGRADEGRADEEXCEPTIONRATIO){获取每秒异常的次数doubleexceptionclusterNode。exceptionQps();获取每秒成功的次数doublesuccessclusterNode。successQps();获取每秒总调用次数doubletotalclusterNode。totalQps();IftotalamountislessthanminRequestAmount,therequestwillpass。如果总调用次数少于5,那么不进行降级if(totalminRequestAmount){returntrue;}Inthesamealignedstatistictimewindow,success(aka。completedcount)exceptioncountnonexceptioncount(realSuccess)doublerealSuccesssuccessexception;if(realSuccess0exceptionminRequestAmount){returntrue;}if(exceptionsuccesscount){returntrue;}}。。。。。。returnfalse;
这个方法中获取成功调用的Qps和异常调用的Qps,验证后,然后求一下比率,如果没有大于count,那么就返回true,否则返回false抛出异常。
们再进入到exceptionQps方法中看一下:publicdoubleexceptionQps(){returnrollingCounterInSecond。exception()rollingCounterInSecond。getWindowIntervalInSec();}
rollingCounterInSecond。getWindowIntervalInSec方法是表示窗口的时间长度,用秒来表示。这里返回的是1。根据异常数降级DEGRADEGRADEEXCEPTIONCOUNTif(gradeRuleConstant。DEGRADEGRADEEXCEPTIONCOUNT){doubleexceptionclusterNode。totalException();if(exceptioncount){returntrue;}}
根据异常数降级是非常的直接的,直接根据统计的异常总次数判断是否超过count。