自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一文了解限流策略的原理與實(shí)現(xiàn)

網(wǎng)絡(luò) 網(wǎng)絡(luò)管理
在實(shí)際業(yè)務(wù)場景中,需要根據(jù)實(shí)際情況合理設(shè)置閾值和限流策略,避免對(duì)真實(shí)用戶請(qǐng)求的過度限制。限流系統(tǒng)只是保障系統(tǒng)穩(wěn)定的手段,而不是目的,因此需要根據(jù)實(shí)際情況來制定相應(yīng)的限流策略,既要保障系統(tǒng)穩(wěn)定,又要保證用戶體驗(yàn)和業(yè)務(wù)效益。

引言

限流策略主要用來控制在高并發(fā)、大流量的場景中對(duì)服務(wù)接口請(qǐng)求的速率。

比如雙十一秒殺、搶購、搶票、搶單等場景。

舉個(gè)例子,假設(shè)某個(gè)接口能夠扛住的QPS為1k,這時(shí)有1w個(gè)請(qǐng)求進(jìn)來,經(jīng)過限流模塊,會(huì)先放1k個(gè)請(qǐng)求,其余的請(qǐng)求會(huì)阻塞一段時(shí)間。不簡單粗暴地返回404,讓客戶端重試,同時(shí)又能起到流量削峰的作用。

在業(yè)務(wù)迭代開發(fā)過程中,系統(tǒng)的穩(wěn)定性和可靠性變得越來越重要,其中,限流算法是一種非常重要的技術(shù)手段之一。

限流算法可以有效地幫助系統(tǒng)控制請(qǐng)求的流量,防止系統(tǒng)因?yàn)榱髁窟^大而崩潰。在高并發(fā)的情況下,如果沒有限流機(jī)制,系統(tǒng)可能會(huì)因?yàn)檎?qǐng)求過多而導(dǎo)致響應(yīng)變慢,甚至癱瘓。此外,限流算法還可以保護(hù)系統(tǒng)免受惡意攻擊、惡意爬蟲等不良行為的侵害,提高系統(tǒng)的安全性和穩(wěn)定性。

本文我們將基于限流策略,討論常見的限流算法的實(shí)現(xiàn)方式,以及如何從0到1設(shè)計(jì)一套可用的限流實(shí)現(xiàn)方案。

1. 簡介

設(shè)計(jì)一套限流算法主要包含以下三個(gè)步驟:

  • 流量統(tǒng)計(jì):記錄在特定時(shí)間段內(nèi)通過的流量數(shù),為后續(xù)限流判斷提供依據(jù)。
  • 限流判斷:判斷當(dāng)前的流量是否可以正常通過。
  • 流量控制:對(duì)于已被限流的請(qǐng)求,需要進(jìn)行的特殊處理。

2. 流量統(tǒng)計(jì)

流量統(tǒng)計(jì)主要有兩種方式:固定窗口統(tǒng)計(jì)和滑動(dòng)窗口統(tǒng)計(jì)。

2.1 固定窗口統(tǒng)計(jì)

固定窗口統(tǒng)計(jì)是將時(shí)間劃分為固定長度的時(shí)間窗口,并在每個(gè)時(shí)間窗口內(nèi)統(tǒng)計(jì)通過系統(tǒng)的請(qǐng)求數(shù)量。例如,下圖中將時(shí)間劃分為1秒的時(shí)間窗口,統(tǒng)計(jì)每秒通過系統(tǒng)的請(qǐng)求數(shù)量。在固定窗口統(tǒng)計(jì)中,每個(gè)時(shí)間窗口的計(jì)數(shù)器都會(huì)在窗口結(jié)束時(shí)清零,重新開始統(tǒng)計(jì)下一個(gè)窗口的請(qǐng)求數(shù)量。

圖片

這種統(tǒng)計(jì)方式簡單易懂,實(shí)現(xiàn)簡單,但是在流量不均勻的情況下容易出現(xiàn)突發(fā)流量問題,導(dǎo)致限流不準(zhǔn)確。如下圖所示,假設(shè)限流設(shè)置為1秒內(nèi)通過qps數(shù)為2,由于在1s的時(shí)候統(tǒng)計(jì)窗口清零,對(duì)于500ms-1000ms這個(gè)區(qū)間內(nèi)通過的2條請(qǐng)求沒有記憶,1000ms-1500ms這個(gè)區(qū)間內(nèi)的請(qǐng)求能正常通過,但實(shí)際上在500ms-1500ms這個(gè)區(qū)間的請(qǐng)求數(shù)已經(jīng)是3了,超過設(shè)定的2的限流值,在極限情況下,固定窗口的真實(shí)流量可能達(dá)到限流值的2倍。

圖片

由于固定窗口實(shí)現(xiàn)簡單,在對(duì)限流準(zhǔn)確度要求不高的情況下,也經(jīng)常有使用到,以下是Apinto網(wǎng)關(guān)用固定窗口進(jìn)行限流的實(shí)際場景應(yīng)用。

//固定窗口結(jié)構(gòu)體
type rateTimer struct {
        // 已請(qǐng)求數(shù)量
        requestCount     int64
        // 限制數(shù)量
        limitCount        int64
        timerType int
        expire    time.Duration
        startTime time.Time
}


// 檢查是否超過了限制
func (r *rateTimer) check() bool {
        if time.Now().Sub(r.startTime) > r.expire {
                r.reset()
                return true
        }
        c := atomic.LoadInt64(&r.requestCount)
        localCount := c + 1
        r.add()
        if localCount > r.limitCount {
                return false
        }
        return true
}

2.2 滑動(dòng)窗口統(tǒng)計(jì)

滑動(dòng)窗口統(tǒng)計(jì)是一種流量統(tǒng)計(jì)方式。它將時(shí)間劃分為固定長度的時(shí)間窗口,但每個(gè)時(shí)間窗口的開始和結(jié)束時(shí)間是根據(jù)當(dāng)前時(shí)間動(dòng)態(tài)滑動(dòng)的。在每個(gè)時(shí)間窗口內(nèi),統(tǒng)計(jì)通過系統(tǒng)的請(qǐng)求數(shù)量,并根據(jù)窗口的滑動(dòng)來更新統(tǒng)計(jì)數(shù)據(jù)。

圖片

在滑動(dòng)窗口統(tǒng)計(jì)中主要涉及兩個(gè)概念:

  • 統(tǒng)計(jì)周期:其中統(tǒng)計(jì)周期即為采樣周期,比如設(shè)定1s最多通過2次請(qǐng)求,這里的1s則是統(tǒng)計(jì)周期。
  • 窗口大?。阂粋€(gè)統(tǒng)計(jì)周期內(nèi)的最小統(tǒng)計(jì)單元,比如下圖,1s時(shí)間劃分成4個(gè)小窗口,每個(gè)窗口負(fù)責(zé)的采樣大小即為250ms,窗口越小,一個(gè)統(tǒng)計(jì)周期內(nèi)窗口數(shù)量越多,則統(tǒng)計(jì)越精準(zhǔn)(由于最后一個(gè)小窗口總是處于未完成統(tǒng)計(jì)的狀態(tài),實(shí)際的統(tǒng)計(jì)周期總比設(shè)定的統(tǒng)計(jì)周期要小)。

圖片

滑動(dòng)窗口中小窗口數(shù)據(jù)結(jié)構(gòu)設(shè)計(jì)上需要包含窗口統(tǒng)計(jì)的“開始時(shí)間”以及在需要“被統(tǒng)計(jì)的元素”的基本信息(這里主要是當(dāng)前窗口通過的請(qǐng)求數(shù)),小窗口設(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)如下BucketWrap所示。

//小窗口的設(shè)計(jì)
type BucketWrap struct {
   // BucketStart represents start timestamp of this statistic bucket wrapper.
   BucketStart uint64
   // Value represents the actual data structure of the metrics (e.g. MetricBucket).
   Value atomic.Value
}


type AtomicBucketWrapArray struct {
   // The base address for real data array
   base unsafe.Pointer // 窗口數(shù)組首元素地址
   // The length of slice(array), it can not be modified.
   length int // 窗口數(shù)組的長度
   data   []*BucketWrap //窗口數(shù)組
}

同時(shí),一個(gè)統(tǒng)計(jì)周期是由多個(gè)小窗口順序組合而成,設(shè)計(jì)上為了避免內(nèi)存空間使用上的浪費(fèi),采用原子時(shí)間輪的方式來將小窗口進(jìn)行收尾相連,以循環(huán)隊(duì)列的方式進(jìn)行編排,數(shù)據(jù)結(jié)構(gòu)是AtomicBucketWrapArray,示意圖如下。

圖片

當(dāng)前時(shí)間對(duì)應(yīng)的窗口可以通過計(jì)算時(shí)間戳取模得到。如果請(qǐng)求在當(dāng)前窗口內(nèi),則記錄請(qǐng)求,更新窗口內(nèi)的請(qǐng)求次數(shù)。如果當(dāng)前時(shí)間已經(jīng)超過了當(dāng)前窗口,就開始一個(gè)新的采樣周期,即重置窗口開始時(shí)間和請(qǐng)求計(jì)數(shù)。

比如此刻的時(shí)間戳是300ms,計(jì)算當(dāng)前時(shí)刻的下標(biāo)是(300/200)%8=1,當(dāng)前窗口的開始時(shí)間是200ms;通過計(jì)算出來的窗口的開始時(shí)間與當(dāng)前時(shí)間一致,則記錄請(qǐng)求。如果時(shí)間劃撥到了下一個(gè)采樣周期,比如此刻時(shí)間是1801ms,計(jì)算的下標(biāo)是(1801/200)%8=1,開始時(shí)間是1800ms,由于窗口記錄的開始時(shí)間是200ms,則表示當(dāng)前窗口的數(shù)據(jù)超采樣周期了,將下標(biāo)為1的窗口開始時(shí)間重置為1800ms,并對(duì)重置窗口記錄,作為新的采樣周期進(jìn)行統(tǒng)計(jì)計(jì)數(shù)。

// 計(jì)算開始時(shí)間
func calculateStartTime(now uint64, bucketLengthInMs uint32) uint64 {
   return now - (now % uint64(bucketLengthInMs))
}
// 窗口下標(biāo)位置
func (la *LeapArray) calculateTimeIdx(now uint64) int {
    timeId := now / uint64(la.bucketLengthInMs)
    return int(timeId) % la.array.length
}

圖片

要獲取滑動(dòng)窗口采樣周期內(nèi)通過的請(qǐng)求數(shù),主要方式是將原子時(shí)間輪進(jìn)行遍歷,將符合條件的采樣窗口中請(qǐng)求數(shù)進(jìn)行累加統(tǒng)計(jì)。

// 匹配符合條件的窗口
func (la *LeapArray) ValuesConditional(now uint64, predicate base.TimePredicate) []*BucketWrap {
   if now <= 0 {
      return make([]*BucketWrap, 0)
   }
   ret := make([]*BucketWrap, 0, la.array.length)
   for i := 0; i < la.array.length; i++ {
      ww := la.array.get(i)
      if ww == nil || la.isBucketDeprecated(now, ww) || !predicate(atomic.LoadUint64(&ww.BucketStart)) {
         continue
      }
      ret = append(ret, ww)
   }
   return ret
}

3. 限流判斷

通過上述采樣窗口的設(shè)計(jì),我們可以獲取任何一個(gè)采樣周期內(nèi)通過的請(qǐng)求數(shù)。通過流量統(tǒng)計(jì),我們可以得到當(dāng)前時(shí)間窗口內(nèi)的請(qǐng)求量和相關(guān)數(shù)據(jù),將其與限流規(guī)則進(jìn)行比較,以判斷當(dāng)前請(qǐng)求是否滿足通過條件。如果請(qǐng)求滿足通過條件,則可以直接通過,否則需要進(jìn)行限流措施。

常用的限流判斷方式是令牌桶算法。該算法基于令牌桶的概念,即以固定的速率向令牌桶中添加令牌。每次請(qǐng)求需要從令牌桶中獲取一個(gè)令牌才能被處理。如果令牌桶中沒有足夠的令牌,則請(qǐng)求將被暫時(shí)阻塞或拒絕,直到令牌桶中有足夠的令牌可以被獲取。

圖片

限流判斷的核心在于計(jì)算當(dāng)前時(shí)刻允許通過的令牌數(shù),即token的計(jì)算策略。主要的計(jì)算策略包括固定閾值、預(yù)熱以及內(nèi)存自適應(yīng)三種。

3.1 固定閾值(Threshold)

這種token計(jì)算策略比較簡單,它的意思是在一個(gè)統(tǒng)計(jì)周期內(nèi)允許通過的請(qǐng)求數(shù)是固定的。只需要比較統(tǒng)計(jì)周期內(nèi)統(tǒng)計(jì)的通過請(qǐng)求數(shù)和閾值,就能判斷當(dāng)前請(qǐng)求是否需要被限流。

func (d *DirectTrafficShapingCalculator) CalculateAllowedTokens(uint32, int32) float64 {
   return d.threshold
}

然而,固定閾值的方式存在一個(gè)問題,即在流量突增的情況下,通過的請(qǐng)求數(shù)會(huì)一瞬間達(dá)到閾值,容易對(duì)下游系統(tǒng)造成較大壓力,簡單來說,過剛易折,因此,另一種提前預(yù)熱的策略應(yīng)運(yùn)而生。

3.2 預(yù)熱(WarmUp)

基于固定閾值的token計(jì)算方案存在一個(gè)問題,即在流量突增的情況下,通過的請(qǐng)求數(shù)會(huì)一瞬間達(dá)到閾值,容易對(duì)下游系統(tǒng)造成較大壓力。因此,期望流量能夠經(jīng)過一段時(shí)間的預(yù)熱再達(dá)到閾值,這樣能給下游系統(tǒng)一定的緩沖時(shí)間。

下圖展示了預(yù)熱(冷啟動(dòng))過程中允許通過請(qǐng)求數(shù)隨時(shí)間變化的關(guān)系圖。該方案的主要設(shè)計(jì)要求包括:

  • 當(dāng)流量較低時(shí),不進(jìn)行限流。(下圖1->3)
  • 當(dāng)流量達(dá)到冷啟動(dòng)閾值時(shí),觸發(fā)系統(tǒng)的冷啟動(dòng)策略。(下圖3)
  • 經(jīng)過一段時(shí)間的預(yù)熱后,允許通過的請(qǐng)求數(shù)達(dá)到設(shè)定的閾值,并保持不變。(下圖2)
  • 當(dāng)流量下降后再次突增時(shí),同樣需要再次觸發(fā)冷啟動(dòng)策略。

圖片

為了滿足設(shè)計(jì)要求,我們需要設(shè)計(jì)一個(gè)預(yù)熱算法,其中啟動(dòng)閾值的設(shè)計(jì)非常關(guān)鍵。為此,我們引入了一個(gè)冷卻因子的概念(coldFactor),它控制著觸發(fā)冷啟動(dòng)的先決條件。具體來說,觸發(fā)冷啟動(dòng)所需的請(qǐng)求量為 Threshold/coldFactor,如下圖所示??梢钥闯?,冷卻因子越小,啟動(dòng)預(yù)熱的閾值就越高。例如,當(dāng)冷卻因子為2時(shí),需要達(dá)到閾值的一半才會(huì)開始啟動(dòng)預(yù)熱。

圖片

在預(yù)熱過程中間,需要設(shè)計(jì)一些變量來控制令牌桶的運(yùn)作。具體來說,我們可以采用以下的變量:

  • storeToken:代表令牌桶中當(dāng)前的令牌數(shù)。該變量與允許通過的請(qǐng)求數(shù)量成負(fù)相關(guān),即storeToken越小,允許通過的請(qǐng)求越多,直到達(dá)到指定的閾值。
  • maxToken:代表令牌桶的最大容量,在預(yù)熱啟動(dòng)時(shí),storeToken的值為maxToken。
  • warningToken:代表令牌桶的預(yù)警數(shù)量,在預(yù)熱結(jié)束時(shí),storeToken的值為warningToken。
  • aboveToken:代表距離預(yù)熱結(jié)束還剩余的令牌數(shù)量,即storeToken與warningToken的差值。這個(gè)變量用于輔助計(jì)算當(dāng)前允許通過的請(qǐng)求數(shù)量。
  • slope:代表斜率,用來計(jì)算生成每個(gè)令牌所需的時(shí)間間隔。
warningToken := uint64((float64(rule.WarmUpPeriodSec) * rule.Threshold) / float64(rule.WarmUpColdFactor-1))


maxToken := warningToken + uint64(2*float64(rule.WarmUpPeriodSec)*rule.Threshold/float64(1.0+rule.WarmUpColdFactor))


slope := float64(rule.WarmUpColdFactor-1.0) / rule.Threshold / float64(maxToken-warningToken)




//允許通過過請(qǐng)求數(shù)計(jì)算,當(dāng)restToken=warningToken預(yù)熱過程結(jié)束
if restToken >= int64(c.warningToken) {
    aboveToken := restToken - int64(c.warningToken)
    warningQps := math.Nextafter(1.0/(float64(aboveToken)*c.slope+1.0/c.threshold), math.MaxFloat64)
    return warningQps
} else {
    return c.threshold
}

圖片

以下是生產(chǎn)令牌的條件:

  • 達(dá)到 warningToken 閾值:即預(yù)熱階段結(jié)束并到達(dá)指定閾值。
  • 通過的請(qǐng)求數(shù)passQps 低于Threshold/coldFactor:未滿足預(yù)熱條件,正常生產(chǎn)令牌。

綜上來說,在遇見突發(fā)流量的預(yù)熱過程中會(huì)停止令牌的生成,此過程會(huì)不斷消耗令牌,直到桶里的令牌數(shù)到達(dá)warningToken,結(jié)束預(yù)熱,重新生產(chǎn)令牌。

oldValue := atomic.LoadInt64(&c.storedTokens)
if oldValue < int64(c.warningToken) {
           newValue = int64(float64(oldValue) + (float64(currentTime)-float64(atomic.LoadUint64(&c.lastFilledTime)))*c.threshold/1000.0)
} else if oldValue > int64(c.warningToken) {
    if passQps < float64(uint32(c.threshold)/c.coldFactor) {
        newValue = int64(float64(oldValue) + float64(currentTime-atomic.LoadUint64(&c.lastFilledTime))*c.threshold/1000.0)
    }
}

預(yù)熱過程(上圖從右往左看):

  • 當(dāng)流量通過較少時(shí),令牌桶不斷填充新的令牌,因?yàn)槲催_(dá)到預(yù)熱閾值(threshold/coldFactor)且消耗的令牌數(shù)少于分配的令牌數(shù),令牌桶中的 storeToken 逐漸填滿,接近于 maxToken后保持穩(wěn)定。
  • 當(dāng)流量突然增加時(shí),達(dá)到預(yù)熱閾值,此時(shí)令牌桶停止生成新令牌,但由于不斷有請(qǐng)求通過,令牌桶中的令牌不斷消耗,導(dǎo)致 storeToken 從右上角的 maxToken 向左下角的 warningToken 移動(dòng)。
  • 經(jīng)過預(yù)設(shè)的預(yù)熱時(shí)間,令牌桶容量達(dá)到 warningToken 預(yù)警數(shù)量,此時(shí) aboveToken 為 0,預(yù)熱結(jié)束,允許的通過請(qǐng)求數(shù)達(dá)到最大閾值,此時(shí)生產(chǎn)的令牌與消耗的令牌相等,令牌桶中令牌數(shù)保持穩(wěn)定。

對(duì)于預(yù)熱我們做了一個(gè)仿真,以下是仿真的過程,在 Threshold 設(shè)定為 10,codeFactor 設(shè)定為 3 的情況下,參數(shù)隨時(shí)間變化的情況如下圖所示。

  • 第一階段:流量突增,正常冷啟動(dòng)過程,此時(shí)storeToken從最大值往warningToken移動(dòng),允許通過的流量逐步上升到指定的閾值10
  • 第二階段:限流階段,超過閾值10的請(qǐng)求都被限流
  • 第三階段:請(qǐng)求量下降到2,在Threshold/coldFactor(3.33)以下,正常為storeToken分配令牌,storeToken主鍵補(bǔ)充到maxToken后停止增加,此時(shí)請(qǐng)求都正常通過
  • 第四階段:流量再次突增,重復(fù)冷啟動(dòng)的過程直到達(dá)到請(qǐng)求閾值
  • 第五階段:限流階段
  • 第六階段:請(qǐng)求量下降到4,小于閾值且大于Threshold/coldFactor(3.33),此時(shí)storeToken在小于warningToken時(shí)候正常分配令牌,在大于warningToken的時(shí)候停止分配令牌,但會(huì)按實(shí)際的請(qǐng)求量消耗令牌,從而使得storeToen在warningToken附近左右橫跳。

通過仿真可以發(fā)現(xiàn),在面對(duì)突發(fā)流量時(shí),真實(shí)允許通過的請(qǐng)求量需要經(jīng)過一段時(shí)間的預(yù)熱才能到達(dá)指定閾值。并且隨著真實(shí)請(qǐng)求量的變化,預(yù)熱過程可以來回進(jìn)行,符合預(yù)熱設(shè)計(jì)的預(yù)期。

圖片

3.3 內(nèi)存自適應(yīng)

這是一種根據(jù)機(jī)器使用內(nèi)存的多少來動(dòng)態(tài)調(diào)節(jié)token數(shù)量的計(jì)算方式。其核心思想是在內(nèi)存使用較少的情況下,允許通過的請(qǐng)求數(shù)量越高;而在內(nèi)存使用較多的情況下,允許通過的請(qǐng)求數(shù)量將會(huì)降低。該方式會(huì)根據(jù)設(shè)定的閾值范圍,隨著內(nèi)存使用量的增加而線性調(diào)整。

{
   Resource:               resName,
   TokenCalculateStrategy: flow.MemoryAdaptive,
   ControlBehavior:        flow.Reject,
   StatIntervalInMs:       1000,
   LowMemUsageThreshold:   1000, // 低水位限流閾值
   HighMemUsageThreshold:  100,  // 高水位限流閾值
   MemLowWaterMarkBytes:  1024,  // 低水位內(nèi)存字節(jié)
   MemHighWaterMarkBytes: 2048,  // 高水位內(nèi)存字節(jié)
}

在上述配置中,下圖顯示了內(nèi)存實(shí)際使用量與允許通過請(qǐng)求量的變化關(guān)系。然而,在實(shí)際線上情況下,大部分情況下是由于請(qǐng)求量增長導(dǎo)致CPU增加,而不是因?yàn)閮?nèi)存使用量突然增加而需要進(jìn)行限流,因此這種限流方式使用較少,或者可以采用類似的思路來實(shí)現(xiàn)基于cpu的自適應(yīng)方式的限流方式的開發(fā)。

圖片

4. 流量控制

根據(jù)限流判斷的結(jié)果,對(duì)于需要進(jìn)行流量控制的請(qǐng)求通常有兩種方式:一種是直接拒絕請(qǐng)求,返回 HTTP 狀態(tài)碼 429;另一種是阻塞請(qǐng)求,控制請(qǐng)求速率,并在一段時(shí)間后再進(jìn)行后續(xù)請(qǐng)求操作。常用的算法是漏桶算法。

漏桶算法是一種流量整形算法,可用于平滑網(wǎng)絡(luò)流量、限制數(shù)據(jù)傳輸速率。其基本原理是,將數(shù)據(jù)以恒定的速率流入一個(gè)固定大小的漏桶中。當(dāng)漏桶已滿時(shí),多余的數(shù)據(jù)將溢出并被丟棄。每次請(qǐng)求時(shí),先從漏桶中獲取令牌。若令牌不足,則請(qǐng)求被拒絕。

具體來說,漏桶算法會(huì)維護(hù)一個(gè)固定大小的漏桶,并以固定的速率流出數(shù)據(jù)。每當(dāng)一個(gè)請(qǐng)求到達(dá)時(shí),漏桶中的容量會(huì)相應(yīng)減少請(qǐng)求數(shù)據(jù)量。如果此時(shí)容量不足,則請(qǐng)求被拒絕;否則,容量不變,請(qǐng)求被允許通過。

圖片

具體實(shí)現(xiàn)上來看,桶的大小由緩沖時(shí)間間隔與每個(gè)排隊(duì)請(qǐng)求的時(shí)間片大小決定,假設(shè)時(shí)間間隔是1s,每個(gè)請(qǐng)求的排隊(duì)時(shí)長是200ms,整個(gè)桶大小為5,可以緩沖5個(gè)請(qǐng)求作為排隊(duì)的請(qǐng)求序列,通過sleep后執(zhí)行的方式進(jìn)行后續(xù)請(qǐng)求,超出的請(qǐng)求會(huì)直接被拒絕。

圖片

漏桶單元測試:設(shè)定桶的允許的時(shí)間間隔是2s,每個(gè)請(qǐng)求的排隊(duì)時(shí)間200ms,15個(gè)請(qǐng)求進(jìn)入之后的每個(gè)請(qǐng)求的狀態(tài)值與等待觸發(fā)執(zhí)行的時(shí)間如下所示:

圖片

至此,我們完成了一整套的限流系統(tǒng)的設(shè)計(jì)過程,過程中針對(duì)計(jì)數(shù)器、令牌桶、漏桶原理等主要應(yīng)用場景和結(jié)合各自特點(diǎn)進(jìn)行了闡述。

5. 應(yīng)用

在實(shí)際業(yè)務(wù)場景中,限流被廣泛應(yīng)用于秒殺、活動(dòng)抽獎(jiǎng)、網(wǎng)關(guān)等場景。網(wǎng)關(guān)服務(wù),通常用于進(jìn)行流量的轉(zhuǎn)發(fā)和預(yù)處理。限流也是這套網(wǎng)關(guān)系統(tǒng)中必不可少的環(huán)節(jié),通過配置滑動(dòng)窗口形式的閾值和預(yù)熱等較為常用的限流算法,能夠有效地為接入的系統(tǒng)提供限流能力的支持。

6. 總結(jié)

上述過程中,本文從實(shí)際業(yè)務(wù)場景出發(fā),從流量統(tǒng)計(jì),限流判斷,流量控制三方面討論了如何設(shè)計(jì)一整套功能完備的限流系統(tǒng),并結(jié)合源碼分析,模擬仿真等手段闡述了限流系統(tǒng)各個(gè)環(huán)節(jié)在限流中所起到的作用。

在實(shí)際業(yè)務(wù)場景中,需要根據(jù)實(shí)際情況合理設(shè)置閾值和限流策略,避免對(duì)真實(shí)用戶請(qǐng)求的過度限制。限流系統(tǒng)只是保障系統(tǒng)穩(wěn)定的手段,而不是目的,因此需要根據(jù)實(shí)際情況來制定相應(yīng)的限流策略,既要保障系統(tǒng)穩(wěn)定,又要保證用戶體驗(yàn)和業(yè)務(wù)效益。限流系統(tǒng)需要不斷優(yōu)化和完善,才能更好地適應(yīng)不同的業(yè)務(wù)場景和流量變化。

責(zé)任編輯:武曉燕 來源: 架構(gòu)精進(jìn)之路
相關(guān)推薦

2020-01-02 09:57:09

Redis訂閱發(fā)布

2022-12-21 08:40:05

限流器分布式限流

2023-02-24 15:24:14

MySQL數(shù)據(jù)庫管理分庫分表

2020-12-08 20:20:15

神經(jīng)網(wǎng)絡(luò)深度學(xué)習(xí)機(jī)器學(xué)習(xí)

2020-08-27 07:34:50

Zookeeper數(shù)據(jù)結(jié)構(gòu)

2021-08-01 08:05:39

Linux信號(hào)原理

2023-09-07 07:17:01

KubernetesCRI標(biāo)準(zhǔn)

2024-02-01 11:57:31

this指針代碼C++

2020-12-24 18:48:36

二維碼二進(jìn)制條形碼

2023-11-20 08:18:49

Netty服務(wù)器

2023-04-26 15:43:24

容器編排容器編排工具

2022-02-25 07:34:36

MQTT協(xié)議RabbitMQ

2022-06-08 08:11:56

威脅建模網(wǎng)絡(luò)安全網(wǎng)絡(luò)攻擊

2023-11-06 08:16:19

APM系統(tǒng)運(yùn)維

2022-11-11 19:09:13

架構(gòu)

2022-06-06 12:25:51

邏輯炸彈惡意代碼

2020-12-29 07:32:59

Redis 列表數(shù)據(jù)

2020-09-27 11:55:20

FTPFTPSSFTP

2023-12-26 07:33:45

Redis持久化COW

2022-10-28 13:48:24

Notebook數(shù)據(jù)開發(fā)機(jī)器學(xué)習(xí)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)