亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

關(guān)于Sentinel中冷啟動限流原理WarmUpController

 更新時(shí)間:2023年04月26日 16:20:10   作者:@Kong  
這篇文章主要介紹了關(guān)于Sentinel中冷啟動限流原理WarmUpController,具有很好的參考價(jià)值,希望對大家有所幫助。

冷啟動

所謂冷啟動,或預(yù)熱是指,系統(tǒng)長時(shí)間處理低水平請求狀態(tài),當(dāng)大量請求突然到來時(shí),并非所有請求都放行,而是慢慢的增加請求,目的時(shí)防止大量請求沖垮應(yīng)用,達(dá)到保護(hù)應(yīng)用的目的。

Sentinel中冷啟動是采用令牌桶算法實(shí)現(xiàn)。

令牌桶算法圖例如下:

在這里插入圖片描述

預(yù)熱模型

Sentinel中的令牌桶算法,是參照Google Guava中的RateLimiter,在學(xué)習(xí)Sentinel中預(yù)熱算法之前,先了解下整個(gè)預(yù)熱模型,如下圖:

在這里插入圖片描述

Guava中預(yù)熱是通過控制令牌的生成時(shí)間,而Sentinel中實(shí)現(xiàn)不同:

  • 不控制每個(gè)請求通過的時(shí)間間隔,而是控制每秒通過的請求數(shù)。
  • 在Guava中,冷卻因子coldFactor固定為3,上圖中②是①的兩倍
  • Sentinel增加冷卻因子coldFactor的作用,在Sentinel模型中,②是①的(coldFactor-1)倍,coldFactor默認(rèn)為3,可以通過csp.sentinel.flow.cold.factor參數(shù)修改

原理分析

Sentinel中冷啟動對應(yīng)的FlowRule配置為RuleConstant.CONTROL_BEHAVIOR_WARM_UP,對應(yīng)的Controller為WarmUpController,首先了解其中的屬性和構(gòu)造方法:

  • count:FlowRule中設(shè)定的閾值
  • warmUpPeriodSec:系統(tǒng)預(yù)熱時(shí)間,代表上圖中的②
  • coldFactor:冷卻因子,默認(rèn)為3,表示倍數(shù),即系統(tǒng)最"冷"時(shí)(令牌桶飽和時(shí)),令牌生成時(shí)間間隔是正常情況下的多少倍
  • warningToken:預(yù)警值,表示進(jìn)入預(yù)熱或預(yù)熱完畢
  • maxToken:最大可用token值,計(jì)算公式:warningToken+(2*時(shí)間*閾值)/(1+因子),默認(rèn)情況下為warningToken的2倍
  • slope:斜度,(coldFactor-1)/count/(maxToken-warningToken),用于計(jì)算token生成的時(shí)間間隔,進(jìn)而計(jì)算當(dāng)前token生成速度,最終比較token生成速度與消費(fèi)速度,決定是否限流
  • storedTokens:姑且可以理解為令牌桶中令牌的數(shù)量
public class WarmUpController implements TrafficShapingController {
	// FlowRule中設(shè)置的閾值
    protected double count;
    // 冷卻因子,默認(rèn)為3,通過SentinelConfig加載,可以修改
    private int coldFactor;
    // 預(yù)警token數(shù)量
    protected int warningToken = 0;
    // 最大token數(shù)量
    private int maxToken;
    // 斜率,用于計(jì)算當(dāng)前生成token的時(shí)間間隔,即生成速率
    protected double slope;
	// 令牌桶中剩余令牌數(shù)
    protected AtomicLong storedTokens = new AtomicLong(0);
    // 最后一次添加令牌的時(shí)間戳
    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;
		// 默認(rèn)為3
        this.coldFactor = coldFactor;
        // thresholdPermits = 0.5 * warmupPeriod / stableInterval.
        // warningToken = 100;
        // 計(jì)算預(yù)警token數(shù)量
        // 例如 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數(shù)量=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設(shè)定閾值count=5,即1s內(nèi)QPS閾值為5,設(shè)置的預(yù)熱時(shí)間默認(rèn)為10s,即warmUpPeriodSec=10,冷卻因子coldFactor默認(rèn)為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

接下來學(xué)習(xí),WarmUpController是如何進(jìn)行限流的,進(jìn)入canPass()方法:

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

    return false;
}

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

syncToken():負(fù)責(zé)令牌的生產(chǎn)和滑落

判斷令牌桶中剩余令牌數(shù)

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

仍然以count=5進(jìn)行舉例,警戒線warningToken=25,maxToken=50

假設(shè)令牌桶中剩余令牌數(shù)storedTokens=30,即在預(yù)熱范圍內(nèi),此時(shí)restToken=30,slope=0.016,則aboveToken=30-25=5

由斜率slope推導(dǎo)當(dāng)前token生成時(shí)間間隔:(restToken-warningToken)*slope+stableInterval=5*0.016+1/5=0.28,即280ms生成一個(gè)token

此時(shí)1s內(nèi)生成token的數(shù)量=1/0.28≈4,即1s內(nèi)生成4個(gè)token

假設(shè)當(dāng)前窗口通過的請求數(shù)量passQps=4,acquiredCount=1,此時(shí)passQps+acquiredCount=5>4,即令牌消耗速度大于生產(chǎn)速度,則限流

  • 如果剩余令牌數(shù)小于警戒值,說明系統(tǒng)已經(jīng)處于高水位,請求穩(wěn)定,則直接判斷QPS與閾值,超過閾值則限流

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

獲取當(dāng)前時(shí)間秒數(shù)currentTime,與lastFilledTime進(jìn)行比較,之所以取秒數(shù),是因?yàn)闀r(shí)間窗口的設(shè)定為1s,若兩個(gè)時(shí)間相等,說明還處于同一秒內(nèi),不進(jìn)行token填充和滑落,避免重復(fù)問題

令牌桶中添加token

  • 當(dāng)流量極大,令牌桶中剩余token遠(yuǎn)低于預(yù)警值時(shí),添加token
  • 處于預(yù)熱節(jié)點(diǎn),單令牌的消耗速度小于系統(tǒng)最冷時(shí)令牌的生成速度,則添加令牌

通過CAS操作,修改storedToken,并進(jìn)行令牌扣減

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

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

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

總結(jié)

Sentinel采用令牌桶算法實(shí)現(xiàn)預(yù)熱限流

系統(tǒng)流量突增,令牌消耗從maxPermits(令牌桶容量)到thresholdPermits(警戒線)所需要的時(shí)間,是從警戒線到0的(coldFactor-1)倍,并非其他博客中的2倍。另外,關(guān)于預(yù)熱模型中②和①的關(guān)系,是通過結(jié)果反推而來,并沒有找到模型定義的官方文檔。

Sentinel限流是針對某時(shí)刻令牌的生成與消耗速度

Sentinel通過比較整秒數(shù),來判斷是否需要進(jìn)行令牌扣減,并通過CAS操作,保證同一時(shí)刻只能由1個(gè)線程成功操作,從而避免多次扣減passQps導(dǎo)致限流失效的問題

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • SpringBoot整合SSO(single sign on)單點(diǎn)登錄

    SpringBoot整合SSO(single sign on)單點(diǎn)登錄

    這篇文章主要介紹了SpringBoot整合SSO(single sign on)單點(diǎn)登錄,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • Java你告訴我 fail-fast 是什么鬼

    Java你告訴我 fail-fast 是什么鬼

    這篇文章主要介紹了Java你告訴我 fail-fast 是什么鬼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • 詳解Spring整合mybatis--Spring中的事務(wù)管理(xml形式)

    詳解Spring整合mybatis--Spring中的事務(wù)管理(xml形式)

    這篇文章主要介紹了Spring整合mybatis--Spring中的事務(wù)管理(xml形式),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-11-11
  • Java二分法查找_動力節(jié)點(diǎn)Java學(xué)院整理

    Java二分法查找_動力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要介紹了Java二分法查找的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • java開源區(qū)塊鏈初始化創(chuàng)世區(qū)塊jdchain服務(wù)搭建

    java開源區(qū)塊鏈初始化創(chuàng)世區(qū)塊jdchain服務(wù)搭建

    這篇文章主要介紹了java開源區(qū)塊鏈初始化創(chuàng)世區(qū)塊jdchain的服務(wù)搭建步驟,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2022-02-02
  • 關(guān)于Spring?Cloud的熔斷器監(jiān)控問題

    關(guān)于Spring?Cloud的熔斷器監(jiān)控問題

    Turbine是一個(gè)聚合Hystrix監(jiān)控?cái)?shù)據(jù)的工具,它可將所有相關(guān)/hystrix.stream端點(diǎn)的數(shù)據(jù)聚合到一個(gè)組合的/turbine.stream中,從而讓集群的監(jiān)控更加方便,接下來通過本文給大家介紹Spring?Cloud的熔斷器監(jiān)控,感興趣的朋友一起看看吧
    2022-01-01
  • Java結(jié)合redis實(shí)現(xiàn)接口防重復(fù)提交

    Java結(jié)合redis實(shí)現(xiàn)接口防重復(fù)提交

    本文主要介紹了Java結(jié)合redis實(shí)現(xiàn)接口防重復(fù)提交,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • JDBC簡介_動力節(jié)點(diǎn)Java學(xué)院整理

    JDBC簡介_動力節(jié)點(diǎn)Java學(xué)院整理

    什么是JDBC?這篇文章就為大家詳細(xì)介紹了Java語言中用來規(guī)范客戶端程序如何來訪問數(shù)據(jù)庫的應(yīng)用程序接口,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • Intellij IDEA安裝lombok插件及使用詳解

    Intellij IDEA安裝lombok插件及使用詳解

    今天小編就為大家分享一篇關(guān)于Intellij IDEA安裝lombok插件及使用詳解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • WebSocket實(shí)現(xiàn)數(shù)據(jù)庫更新時(shí)前端頁面刷新

    WebSocket實(shí)現(xiàn)數(shù)據(jù)庫更新時(shí)前端頁面刷新

    這篇文章主要為大家詳細(xì)介紹了WebSocket實(shí)現(xiàn)數(shù)據(jù)庫更新時(shí)前端頁面刷新,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-04-04

最新評論