Sentinel的流控效果

Sentinel的流控效果有四种类型,都是TrafficShapingController的实现类,分别是DefaultController(默认策略,直接拒绝),WarmUpController(预热启动),RateLimiterController(排队等待),
WarmUpRateLimiterController(预热排队等待)。

DefaultController.canPass(直接拒绝,如果限流允许优先级,并且是基于QPS限流,尝试抢占未来的时间窗口)

public boolean canPass(Node node, int acquireCount, boolean prioritized) {
    //获取当前时间窗口的请求数(或者线程数)
    int curCount = this.avgUsedTokens(node);
    if((double)(curCount + acquireCount) > this.count) {//达到了限流的限制
        //存在优先级,并且是基于QPS的限流阀值类型
        if(prioritized && this.grade == 1) {
            long currentTime = TimeUtil.currentTimeMillis();
            //计算离未来时间窗口需要等待的时间
            long waitInMs = node.tryOccupyNext(currentTime, acquireCount, this.count);
            if(waitInMs < (long)OccupyTimeoutProperty.getOccupyTimeout()) {//小于最大占用超时时间
                //抢占未来的时间窗口
                node.addWaitingRequest(currentTime + waitInMs, acquireCount);
                node.addOccupiedPass(acquireCount);
                //睡眠等待到达未来的时间窗口
                this.sleep(waitInMs);
                throw new PriorityWaitException(waitInMs);
            }
        }
        return false;
    } else {
        return true;
    }
}
private int avgUsedTokens(Node node) {
    return node == null?0:(this.grade == 0?node.curThreadNum():(int)node.passQps());
}
public long tryOccupyNext(long currentTime, int acquireCount, double threshold) {
    //计算一秒内可以通过的请求数
    double maxCount = threshold * (double)IntervalProperty.INTERVAL / 1000.0D;
    //获取未来时间窗口的请求数
    long currentBorrow = this.rollingCounterInSecond.waiting();
    if((double)currentBorrow >= maxCount) {//未来时间窗口的请求数大于超过限制
        //返回最大占用超时时间
        return (long)OccupyTimeoutProperty.getOccupyTimeout();
    } else { 
         //窗口间隔长度
        int windowLength = IntervalProperty.INTERVAL / SampleCountProperty.SAMPLE_COUNT;
        //计算上一个时间窗口开始的时间
        long earliestTime = currentTime - currentTime % (long)windowLength + (long)windowLength - (long)IntervalProperty.INTERVAL;
        int idx = 0;
        //通过的请求数
        for(long currentPass = this.rollingCounterInSecond.pass(); earliestTime < currentTime; ++idx) {
            //当前时间窗口剩余的时间
            long waitInMs = (long)(idx * windowLength + windowLength) - currentTime % (long)windowLength;
            if(waitInMs >= (long)OccupyTimeoutProperty.getOccupyTimeout()) {
                break;
            }
            //当前时间的上一个时间窗口的请求通过数
            long windowPass = this.rollingCounterInSecond.getWindowPass(earliestTime);
            if((double)(currentPass + currentBorrow + (long)acquireCount - windowPass) <= maxCount) {
                return waitInMs;
            }
            //后一个时间窗口的开始时间
            earliestTime += (long)windowLength;
            currentPass -= windowPass;
        }
        return (long)OccupyTimeoutProperty.getOccupyTimeout();
    }
}
public long currentWaiting() {
    this.borrowArray.currentWindow();
    long currentWaiting = 0L;
    List list = this.borrowArray.values();
    MetricBucket window;
    for(Iterator var4 = list.iterator(); var4.hasNext(); currentWaiting += window.pass()) {
        window = (MetricBucket)var4.next();
    }
    return currentWaiting;
}
WarmUpController.canPass(预热启动)

查看WarmUpController的构造函数

public WarmUpController(double count, int warmUpPeriodInSec) {
    this.construct(count, warmUpPeriodInSec, 3);
}
private void construct(double count, int warmUpPeriodInSec, int coldFactor) {
    if(coldFactor <= 1) {
        throw new IllegalArgumentException("Cold factor should be larger than 1");
    } else {
        this.count = count;
        this.coldFactor = coldFactor;
        //剩余token的警戒值,warmUpPeriodInSec(预热时长秒)默认为FlowRule的warmUpPeriodInSec(10)

               //coldFactor 冷启动系数 默认为3,所以当count=1时,warningToken默认为5,maxToken默认为10,slope为0.4

        this.warningToken = (int)((double)warmUpPeriodInSec * count) / (coldFactor - 1);
        this.maxToken = this.warningToken + (int)((double)(2 * warmUpPeriodInSec) * count / (1.0D + (double)coldFactor));
        this.slope = ((double)coldFactor - 1.0D) / count / (double)(this.maxToken - this.warningToken);
    }
}
public boolean canPass(Node node, int acquireCount, boolean prioritized) {
     //每一秒钟通过的请求数
    long passQps = (long)node.passQps();
    //上一个时间窗口通过的请求数
    long previousQps = (long)node.previousPassQps();
    //计算剩余token数
    this.syncToken(previousQps);
    long restToken = this.storedTokens.get();
    if(restToken >= (long)this.warningToken) {
        //计算超出警戒值的token数
        long aboveToken = restToken - (long)this.warningToken;
        //计算当前允许通过的请求数
        double warningQps = Math.nextUp(1.0D / ((double)aboveToken * this.slope + 1.0D / this.count));
        if((double)(passQps + (long)acquireCount) <= warningQps) {
            return true;
        }
    //预热结束,直接判断是否达到限流数
    } else if((double)(passQps + (long)acquireCount) <= this.count) {
        return true;
    }
    return false;
}
protected void syncToken(long passQps) {
    long currentTime = TimeUtil.currentTimeMillis();
    currentTime -= currentTime % 1000L;
    long oldLastFillTime = this.lastFilledTime.get();
    if(currentTime > oldLastFillTime) {
        long oldValue = this.storedTokens.get();
        //获得新的令牌数
        long newValue = this.coolDownTokens(currentTime, passQps);
        if(this.storedTokens.compareAndSet(oldValue, newValue)) {
            //减去上次通过的qps数量,得到当前的实际token数
            long currentValue = this.storedTokens.addAndGet(0L - passQps);
            if(currentValue < 0L) {
                this.storedTokens.set(0L);
            }
            this.lastFilledTime.set(currentTime);
        }

    }
}
private long coolDownTokens(long currentTime, long passQps) {
    //上一次剩余的token数,初始值为0
    long oldValue = this.storedTokens.get();
    long newValue = oldValue;
    //系统初始启动阶段
    if(oldValue < (long)this.warningToken) {
        //初始阶段,oldValue =0,lastFilledTime=0,currentTime 很大,newValue 会得到一个很大的值
        newValue = (long)((double)oldValue + (double)(currentTime - this.lastFilledTime.get()) * this.count / 1000.0D);
      //预热阶段,当前qps小于 count / coldFactor
    } else if(oldValue > (long)this.warningToken && passQps < (long)((int)this.count / this.coldFactor)) {
        newValue = (long)((double)oldValue + (double)(currentTime - this.lastFilledTime.get()) * this.count / 1000.0D);
    }
    return Math.min(newValue, (long)this.maxToken);
}
RateLimiterController.canPass(排队等待)
public boolean canPass(Node node, int acquireCount, boolean prioritized) {
    if(acquireCount <= 0) {
        return true;
    } else if(this.count <= 0.0D) {
        return false;
    } else {
        long currentTime = TimeUtil.currentTimeMillis();
        //计算请求的间隔时间
        long costTime = Math.round(1.0D * (double)acquireCount / this.count * 1000.0D);
        //本次期望通过的时间
        long expectedTime = costTime + this.latestPassedTime.get();
        if(expectedTime <= currentTime) {//期望通过时间小于当前时间,不需要限流
            this.latestPassedTime.set(currentTime);
            return true;
        } else {
            //需要等待的时间
            long waitTime = costTime + this.latestPassedTime.get() - TimeUtil.currentTimeMillis();
            if(waitTime > (long)this.maxQueueingTimeMs) {
                return false;
            } else {
                //计算通过时间
                long oldTime = this.latestPassedTime.addAndGet(costTime);

                try {
                    //重新计算等待时间,防止并发访问
                    waitTime = oldTime - TimeUtil.currentTimeMillis();
                    if(waitTime > (long)this.maxQueueingTimeMs) {//等待时间过长,返回失败
                        this.latestPassedTime.addAndGet(-costTime);
                        return false;
                    } else {
                        if(waitTime > 0L) {
                            //睡眠等待
                            Thread.sleep(waitTime);
                        }

                        return true;
                    }
                } catch (InterruptedException var15) {
                    return false;
                }
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_33513289/article/details/111300718