亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Sentinel中冷啟動限流原理WarmUpController是什么

發布時間:2023-04-26 17:15:13 來源:億速云 閱讀:146 作者:iii 欄目:開發技術

本篇內容介紹了“Sentinel中冷啟動限流原理WarmUpController是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

冷啟動

所謂冷啟動,或預熱是指,系統長時間處理低水平請求狀態,當大量請求突然到來時,并非所有請求都放行,而是慢慢的增加請求,目的時防止大量請求沖垮應用,達到保護應用的目的。

Sentinel中冷啟動是采用令牌桶算法實現。

令牌桶算法圖例如下:

Sentinel中冷啟動限流原理WarmUpController是什么

預熱模型

Sentinel中的令牌桶算法,是參照Google Guava中的RateLimiter,在學習Sentinel中預熱算法之前,先了解下整個預熱模型,如下圖:

Sentinel中冷啟動限流原理WarmUpController是什么

Guava中預熱是通過控制令牌的生成時間,而Sentinel中實現不同:

  • 不控制每個請求通過的時間間隔,而是控制每秒通過的請求數。

  • 在Guava中,冷卻因子coldFactor固定為3,上圖中②是①的兩倍

  • Sentinel增加冷卻因子coldFactor的作用,在Sentinel模型中,②是①的(coldFactor-1)倍,coldFactor默認為3,可以通過csp.sentinel.flow.cold.factor參數修改

原理分析

Sentinel中冷啟動對應的FlowRule配置為RuleConstant.CONTROL_BEHAVIOR_WARM_UP,對應的Controller為WarmUpController,首先了解其中的屬性和構造方法:

  • count:FlowRule中設定的閾值

  • warmUpPeriodSec:系統預熱時間,代表上圖中的②

  • coldFactor:冷卻因子,默認為3,表示倍數,即系統最"冷"時(令牌桶飽和時),令牌生成時間間隔是正常情況下的多少倍

  • warningToken:預警值,表示進入預熱或預熱完畢

  • maxToken:最大可用token值,計算公式:warningToken+(2*時間*閾值)/(1+因子),默認情況下為warningToken的2倍

  • slope:斜度,(coldFactor-1)/count/(maxToken-warningToken),用于計算token生成的時間間隔,進而計算當前token生成速度,最終比較token生成速度與消費速度,決定是否限流

  • storedTokens:姑且可以理解為令牌桶中令牌的數量

public class WarmUpController implements TrafficShapingController {
	// FlowRule中設置的閾值
    protected double count;
    // 冷卻因子,默認為3,通過SentinelConfig加載,可以修改
    private int coldFactor;
    // 預警token數量
    protected int warningToken = 0;
    // 最大token數量
    private int maxToken;
    // 斜率,用于計算當前生成token的時間間隔,即生成速率
    protected double slope;
	// 令牌桶中剩余令牌數
    protected AtomicLong storedTokens = new AtomicLong(0);
    // 最后一次添加令牌的時間戳
    protected AtomicLong lastFilledTime = new AtomicLong(0);
    public WarmUpController(double count, int warmUpPeriodInSec, int coldFactor) {
        construct(count, warmUpPeriodInSec, coldFactor);
    }
    public WarmUpController(double count, int warmUpPeriodInSec) {
        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");
        }
        this.count = count;
		// 默認為3
        this.coldFactor = coldFactor;
        // thresholdPermits = 0.5 * warmupPeriod / stableInterval.
        // warningToken = 100;
        // 計算預警token數量
        // 例如 count=5,warmUpPeriodInSec=10,coldFactor=3,則waringToken=5*10/2=25
        warningToken = (int)(warmUpPeriodInSec * count) / (coldFactor - 1);
        // / maxPermits = thresholdPermits + 2 * warmupPeriod / (stableInterval + coldInterval)
        // maxToken = 200
        // 最大token數量=25+2*10*5/4=50
        maxToken = warningToken + (int)(2 * warmUpPeriodInSec * count / (1.0 + coldFactor));
        // slope
        // slope = (coldIntervalMicros - stableIntervalMicros) / (maxPermits- thresholdPermits);
        // 傾斜度=(3-1)/5/(50-25) = 0.016
        slope = (coldFactor - 1.0) / count / (maxToken - warningToken);
    }
}

舉例說明:

FlowRule設定閾值count=5,即1s內QPS閾值為5,設置的預熱時間默認為10s,即warmUpPeriodSec=10,冷卻因子coldFactor默認為3,即count = 5,coldFactor=3,warmUpPeriodSec=10,則

stableInterval=1/count=200ms,coldInterval=coldFactor*stableInterval=600ms
warningToken=warmUpPeriodSec/(coldFactor-1)/stableInterval=(warmUpPeriodSec*count)/(coldFactor-1)=25
maxToken=2warmUpPeriodSec/(stableInterval+coldInterval)+warningToken=warningToken+2warmUpPeriodSeccount/(coldFactor+1)=50
slope=(coldInterval-stableInterval)/(maxToken-warningToken)=(coldFactor-1)/count/(maxToken-warningToken)=0.016

接下來學習,WarmUpController是如何進行限流的,進入canPass()方法:

public boolean canPass(Node node, int acquireCount, boolean prioritized) {
    // 獲取當前1s的QPS
    long passQps = (long) node.passQps();
    // 獲取上一窗口通過的qps
    long previousQps = (long) node.previousPassQps();
    // 生成和滑落token
    syncToken(previousQps);
    // 如果進入了警戒線,開始調整他的qps
    long restToken = storedTokens.get();
    // 如果令牌桶中的token數量大于警戒值,說明還未預熱結束,需要判斷token的生成速度和消費速度
    if (restToken >= warningToken) {
        long aboveToken = restToken - warningToken;
        // 消耗的速度要比warning快,但是要比慢
        // y軸,當前token生成時間 current interval = restToken*slope+stableInterval
        // 計算此時1s內能夠生成token的數量
        double warningQps = Math.nextUp(1.0 / (aboveToken * slope + 1.0 / count));
        // 判斷token消費速度是否小于生成速度,如果是則正常請求,否則限流
        if (passQps + acquireCount <= warningQps) {
            return true;
        }
    } else {
        // 預熱結束,直接判斷是否超過設置的閾值
        if (passQps + acquireCount <= count) {
            return true;
        }
    }

    return false;
}

canPass()方法分為3個階段:

syncToken():負責令牌的生產和滑落

判斷令牌桶中剩余令牌數

  • 如果剩余令牌數大于警戒值,說明處于預熱階段,需要比較令牌的生產速率與令牌的消耗速率。若消耗速率大,則限流;否則請求正常通行

仍然以count=5進行舉例,警戒線warningToken=25,maxToken=50

假設令牌桶中剩余令牌數storedTokens=30,即在預熱范圍內,此時restToken=30,slope=0.016,則aboveToken=30-25=5

由斜率slope推導當前token生成時間間隔:(restToken-warningToken)*slope+stableInterval=5*0.016+1/5=0.28,即280ms生成一個token

此時1s內生成token的數量=1/0.28&asymp;4,即1s內生成4個token

假設當前窗口通過的請求數量passQps=4,acquiredCount=1,此時passQps+acquiredCount=5>4,即令牌消耗速度大于生產速度,則限流

  • 如果剩余令牌數小于警戒值,說明系統已經處于高水位,請求穩定,則直接判斷QPS與閾值,超過閾值則限流

接下來分析Sentinel是如何生產及滑落token的,進入到syncToken()方法:

獲取當前時間秒數currentTime,與lastFilledTime進行比較,之所以取秒數,是因為時間窗口的設定為1s,若兩個時間相等,說明還處于同一秒內,不進行token填充和滑落,避免重復問題

令牌桶中添加token

  • 當流量極大,令牌桶中剩余token遠低于預警值時,添加token

  • 處于預熱節點,單令牌的消耗速度小于系統最冷時令牌的生成速度,則添加令牌

通過CAS操作,修改storedToken,并進行令牌扣減

protected void syncToken(long passQps) {
    long currentTime = TimeUtil.currentTimeMillis();
    // 獲取整秒數
    currentTime = currentTime - currentTime % 1000;
    // 上一次的操作時間
    long oldLastFillTime = lastFilledTime.get();
    // 判斷成立,如果小于,說明可能出現了時鐘回撥
    // 如果等于,說明當前請求都處于同一秒內,則不進行token添加和滑落操作,避免的重復扣減
    // 時間窗口的跨度為1s
    if (currentTime <= oldLastFillTime) {
        return;
    }
    // token數量
    long oldValue = storedTokens.get();
    long newValue = coolDownTokens(currentTime, passQps);
    // 重置token數量
    if (storedTokens.compareAndSet(oldValue, newValue)) {
        // token滑落,即token消費
        // 減去上一個時間窗口的通過請求數
        long currentValue = storedTokens.addAndGet(0 - passQps);
        if (currentValue < 0) {
            storedTokens.set(0L);
        }
        // 設置最后添加令牌時間
        lastFilledTime.set(currentTime);
    }

}
private long coolDownTokens(long currentTime, long passQps) {
    long oldValue = storedTokens.get();
    long newValue = oldValue;

    // 添加令牌的判斷前提條件:
    // 當令牌的消耗程度遠遠低于警戒線的時候
    if (oldValue < warningToken) {
        // 計算過去一段時間內,可以通過的QPS總量
        // 初始加載時,令牌數量達到maxToken
        newValue = (long)(oldValue + (currentTime - lastFilledTime.get()) * count / 1000);
    } else if (oldValue > warningToken) {
        // 處于預熱過程,且消費速度低于冷卻速度,則補充令牌
        if (passQps < (int)count / coldFactor) {
            newValue = (long)(oldValue + (currentTime - lastFilledTime.get()) * count / 1000);
        }
    }
    // 當令牌桶滿了之后,拋棄多余的令牌
    return Math.min(newValue, maxToken);
}

“Sentinel中冷啟動限流原理WarmUpController是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

肃北| 吉首市| 乐陵市| 阿坝| 台中市| 秀山| 开远市| 孙吴县| 黑河市| 玉树县| 田阳县| 阳曲县| 伊宁县| 汝州市| 延吉市| 木兰县| 胶南市| 永平县| 芷江| 邵阳市| 大关县| 乐都县| 永吉县| 安吉县| 沂水县| 南城县| 陆川县| 衡阳县| 涟源市| 霞浦县| 乌拉特后旗| 华坪县| 永新县| 吉林省| 富平县| 高州市| 抚宁县| 喜德县| 徐州市| 育儿| 松滋市|