高並發之限流令牌桶和漏桶算法(一)


在開發高並發系統時有三把利器用來保護系統:緩存、降級和限流

  • 緩存 緩存的目的是提升系統訪問速度和增大系統處理容量
  • 降級 降級是當服務出現問題或者影響到核心流程時,需要暫時屏蔽掉,待高峰或者問題解決后再打開
  • 限流 限流的目的是通過對並發訪問/請求進行限速,或者對一個時間窗口內的請求進行限速來保護系統,一旦達到限制速率則可以拒絕服務、排隊或等待、降級等處理

常用的限流算法

漏桶算法

漏桶算法思路很簡單,水(請求)先進入到漏桶里,漏桶以一定的速度出水,當水流入速度過大會直接溢出,可以看出漏桶算法能強行限制數據的傳輸速率。

 
下面時偽代碼:
public class TokenBucketDemo {
    public long timeStamp = getNowTime();
    public int capacity; // 桶的容量
    public int rate; // 水漏出的速度
    public int water; // 當前水量(當前累積請求數)
    public boolean grant() {
        long now = getNowTime();
        water = max(0, water - (now - timeStamp) * rate); // 先執行漏水,計算剩余水量
        timeStamp = now;
        if ((water + 1) < capacity) {
            // 嘗試加水,並且水還未滿
            water += 1;
            return true;
        }
        else {
            // 水滿,拒絕加水
            return false;
        }
    }
}

 

漏桶算法不能夠有效地使用網絡資源。因為漏桶的漏出速率是固定的參數,所以即使網絡中不存在資源沖突(沒有發生擁塞),漏桶算法也不能使某一個單獨的流突發到端口速率。因此,漏桶算法對於存在突發特性的流量來說缺乏效率。

令牌桶算法

對於很多應用場景來說,除了要求能夠限制數據的平均傳輸速率外,還要求允許某種程度的突發傳輸。這時候漏桶算法可能就不合適了,令牌桶算法更為適合。如圖所示,令牌桶算法的原理是系統會以一個恆定的速度往桶里放入令牌,而如果請求需要被處理,則需要先從桶里獲取一個令牌,當桶里沒有令牌可取時,則拒絕服務。

 

令牌桶算法圖例

 a. 按特定的速率向令牌桶投放令牌

 b. 根據預設的匹配規則先對報文進行分類,不符合匹配規則的報文不需要經過令牌桶的處理,直接發送;

 c. 符合匹配規則的報文,則需要令牌桶進行處理。當桶中有足夠的令牌則報文可以被繼續發送下去,同時令牌桶中的令牌 量按報文的長度做相應的減少;

 d. 當令牌桶中的令牌不足時,報文將不能被發送,只有等到桶中生成了新的令牌,報文才可以發送。這就可以限制報文的流量只能是小於等於令牌生成的速度,達到限制流量的目的。

注意:當令牌不足時,這里報文:

1、可以被丟棄

2、可以排放在隊列中以便當令牌桶中累積了足夠多的令牌時再傳輸

3、可以繼續發送,但需要做特殊標記,網絡過載的時候將這些特殊標記的包丟棄

 偽代碼:

public class TokenBucketDemo {
    public long timeStamp = getNowTime();
    public int capacity; // 桶的容量
    public int rate; // 令牌放入速度
    public int tokens; // 當前令牌數量
    public boolean grant() {
        long now = getNowTime();
        // 先添加令牌
        //min(桶的容量,當前令牌 + 上次請求獲取令牌時間到當前時間內生成的令牌)
        tokens = min(capacity, tokens + (now - timeStamp) * rate);
        timeStamp = now;
        if (tokens < 1) {
            // 若不到1個令牌,則拒絕
            return false;
        }
        else {
            // 還有令牌,領取令牌
            tokens -= 1;
            return true;
        }
    }
}

令牌桶算法臨界問題思考:

場景:在0:59秒的時候有100個請求過來,此時令牌桶有100個token,瞬間通過。1:00的時候又有100個請求,但令牌放入令牌桶是有一定的速率的,假設rate<100,不可能100個請求都通過。避免了計數器算法瞬間請求過大,壓垮系統。

令牌桶和漏桶對比:

  • 令牌桶是按照固定速率往桶中添加令牌,請求是否被處理需要看桶中令牌是否足夠,當令牌數減為零時則拒絕新的請求;

  • 漏桶則是按照常量固定速率流出請求,流入請求速率任意,當流入的請求數累積到漏桶容量時,則新流入的請求被拒絕;

  • 令牌桶限制的是平均流入速率(允許突發請求,只要有令牌就可以處理,支持一次拿3個令牌,4個令牌),並允許一定程度突發流量;

  • 漏桶限制的是常量流出速率(即流出速率是一個固定常量值,比如都是1的速率流出,而不能一次是1,下次又是2),從而平滑突發流入速率;

  • 令牌桶允許一定程度的突發,而漏桶主要目的是平滑流入速率;

  • 兩個算法實現可以一樣,但是方向是相反的,對於相同的參數得到的限流效果是一樣的。

 

參考:

https://www.jianshu.com/p/5d4fe4b2a726

https://www.cnblogs.com/xuwc/p/9123078.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM