4.Sentinel源码分析— Sentinel是如何做到降级的? (2)

这个方法首先会去获取cut的值,如果是true那么就直接进行限流操作。然后会根据resource获取ClusterNode全局节点。往下分别根据三种不同的策略来进行降级。

DEGRADE_GRADE_RT根据响应时间进行降级 if (grade == RuleConstant.DEGRADE_GRADE_RT) { //获取节点的平均响应时间 double rt = clusterNode.avgRt(); if (rt < this.count) { passCount.set(0); return true; } //rtSlowRequestAmount默认是5 // Sentinel will degrade the service only if count exceeds. if (passCount.incrementAndGet() < rtSlowRequestAmount) { return true; } }

如果是根据响应时间进行降级,那么会获取clusterNode的平均响应时间,如果平均响应时间大于所设定的count(默认是毫秒),那么就调用passCount加1,如果passCount大于5,那么直接降级。

所以看到这里我们应该知道根据平均响应时间降级前几个请求即使响应过长也不会立马降级,而是要等到第六个请求到来才会进行降级。

我们进入到clusterNode的avgRt方法中看一下是如何获取到clusterNode的平均响应时间的。

clusterNode是StatisticNode的实例
StatisticNode#avgRt
java public double avgRt() { //获取当前时间窗口内调用成功的次数 long successCount = rollingCounterInSecond.success(); if (successCount == 0) { return 0; } //获取窗口内的响应时间 return rollingCounterInSecond.rt() * 1.0 / successCount; }e

这个方法主要是调用rollingCounterInSecond获取成功次数,然后再获取窗口内的响应时间,用总响应时间除以次数得到平均每次成功调用的响应时间。

在1.Sentinel源码分析—FlowRuleManager加载规则做了什么?中,我已经具体讲述了StatisticNode里面的rollingCounterInMinute实现原理,rollingCounterInMinute是按分钟进行统计的时间窗口。现在我们来讲一下rollingCounterInSecond按秒来进行统计的时间窗口。

在StatisticNode里面初始化rollingCounterInSecond:

private transient volatile Metric rollingCounterInSecond = new ArrayMetric(SampleCountProperty.SAMPLE_COUNT, IntervalProperty.INTERVAL);

在这个初始化的方法里,会传入两个参数,SampleCountProperty.SAMPLE_COUNT的值是2,
IntervalProperty.INTERVAL的值是1000。

我们进入到ArrayMetric的构造方法中:

private final LeapArray<MetricBucket> data; public ArrayMetric(int sampleCount, int intervalInMs) { this.data = new OccupiableBucketLeapArray(sampleCount, intervalInMs); }

在创建ArrayMetric实例的时候会给data创建一个OccupiableBucketLeapArray实例。

OccupiableBucketLeapArray

public OccupiableBucketLeapArray(int sampleCount, int intervalInMs) { // This class is the original "CombinedBucketArray". super(sampleCount, intervalInMs); this.borrowArray = new FutureBucketLeapArray(sampleCount, intervalInMs); }

OccupiableBucketLeapArray继承LeapArray这个抽象类,初始化的时候会调用父类的构造器:
LeapArray

public LeapArray(int sampleCount, int intervalInMs) { AssertUtil.isTrue(sampleCount > 0, "bucket count is invalid: " + sampleCount); AssertUtil.isTrue(intervalInMs > 0, "total time interval of the sliding window should be positive"); //intervalInMs是sampleCount的整数 AssertUtil.isTrue(intervalInMs % sampleCount == 0, "time span needs to be evenly divided"); //每个小窗口的时间跨度 this.windowLengthInMs = intervalInMs / sampleCount; //窗口的长度 this.intervalInMs = intervalInMs; //窗口个数 this.sampleCount = sampleCount; this.array = new AtomicReferenceArray<>(sampleCount); }

OccupiableBucketLeapArray在初始化的时候也会创建一个FutureBucketLeapArray实例赋值给borrowArray。

FutureBucketLeapArray也是继承LeapArray:

public FutureBucketLeapArray(int sampleCount, int intervalInMs) { // This class is the original "BorrowBucketArray". super(sampleCount, intervalInMs); }

直接通过调用父类LeapArray的构造方法进行初始化。

到这里rollingCounterInSecond的创建过程讲完了。

下面我们再回到StatisticNode中,在调用StatisticNode的avgRt方法的时候会调用rollingCounterInSecond.success()方法获取当前时间窗口的调用成功次数:

ArrayMetric#success

public long success() { //设置或更新当前的时间窗口 data.currentWindow(); long success = 0; //获取窗口里有效的Bucket List<MetricBucket> list = data.values(); for (MetricBucket window : list) { success += window.success(); } return success; }

这里的data是的父类是LeapArray,LeapArray里面有一个array数组,用来记录时间窗口,在我们这里是基于秒钟的时间窗口,所以array的大小为2。data的结构图我直接从1.Sentinel源码分析—FlowRuleManager加载规则做了什么?中拿过来:

4.Sentinel源码分析— Sentinel是如何做到降级的?

只不过这里的WindowWrap数组元素只有两个,每一个WindowWrap元素由MetricBucket对象构成,用来统计数据,如:通过次数、阻塞次数、异常次数等~

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zydpsp.html