1. 程式人生 > 其它 >常見的限流演算法

常見的限流演算法

計數器法
計數器法是限流演算法裡最簡單也是最容易實現的一種演算法。比如我們規定,對於A介面來說,我們1分鐘的訪問次數不能超過100個。那麼我們可以這麼做:在一開 始的時候,我們可以設定一個計數器counter,每當一個請求過來
的時候,counter就加1,如果counter的值大於100並且該請求與第一個 請求的間隔時間還在1分鐘之內,那麼說明請求數過多;如果該請求與第一個請求的間隔時間大於1分鐘,且counter的值還在限流範圍內,那麼就重置
counter,具體演算法的示意圖如下:

這個演算法雖然簡單,但是有一個十分致命的問題,那就是臨界問題,我們看下圖:

從上圖中我們可以看到,假設有一個惡意使用者,他在0:59時,瞬間傳送了100個請求,並且1:00又瞬間傳送了100個請求,那麼其實這個使用者在 1秒裡面,瞬間傳送了200個請求。我們剛才規定的是1分鐘最多100個請求,也就是每秒鐘最多1.7個請求,使用者通過在時間視窗的重置節點處突發請求,

可以瞬間超過我們的速率限制。使用者有可能通過演算法的這個漏洞,瞬間壓垮我們的應用。聰明的朋友可能已經看出來了,剛才的問題其實是因為我們統計的精度太低。那麼如何很好地處理這個問題呢?或者說,如何將臨界問題的影響降低呢?我們可以看下面的滑動視窗演算法。
滑動視窗
滑動視窗,又稱rolling window。為了解決這個問題,我們引入了滑動視窗演算法。如果學過TCP網路協議的話,那麼一定對滑動視窗這個名詞不會陌生。下面這張圖,很好地解釋了滑動視窗演算法:

在上圖中,整個紅色的矩形框表示一個時間視窗,在我們的例子中,一個時間視窗就是一分鐘。然後我們將時間視窗進行劃分,比如圖中,我們就將滑動視窗 劃成了6格,所以每格代表的是10秒鐘。每過10秒鐘,我們的時間視窗

就會往右滑動一格。每一個格子都有自己獨立的計數器counter,比如當一個請求 在0:35秒的時候到達,那麼0:30~0:39對應的counter就會加1。那麼滑動視窗怎麼解決剛才的臨界問題的呢?我們可以看上圖,0:59到達的100個請求

會落在灰色的格子中,而1:00到達的請求會落在橘黃色的格 子中。當時間到達1:00時,我們的視窗會往右移動一格,那麼此時時間視窗內的總請求數量一共是200個,超過了限定的100個,所以此時能夠檢測出來觸 發了限流。我再

來回顧一下剛才的計數器演算法,我們可以發現,計數器演算法其實就是滑動視窗演算法。只是它沒有對時間視窗做進一步地劃分,所以只有1格。由此可見,當滑動視窗的格子劃分的越多,那麼滑動視窗的滾動就越平滑,限流的統計就會越精確。

漏桶演算法

漏桶演算法,又稱leaky bucket。為了理解漏桶演算法,我們看一下維基百科上的對於該演算法的示意圖:

從圖中我們可以看到,整個演算法其實十分簡單。首先,我們有一個固定容量的桶,有水流進來,也有水流出去。對於流進來的水來說,我們無法預計一共有多 少水會流進來,也無法預計水流的速度。但是對於流出去的水來說,這個桶可以固定水流出的速率。而且,當桶滿了之後,多餘的水將會溢位

我們將演算法中的水換成實際應用中的請求,我們可以看到漏桶演算法天生就限制了請求的速度。當使用了漏桶演算法,我們可以保證介面會以一個常速速率來處理請求。所以漏桶演算法天生不會出現臨界問題。

令牌桶演算法
令牌桶演算法,又稱token bucket。為了理解該演算法,我們再來看一下維基百科上對該演算法的示意圖:

從圖中我們可以看到,令牌桶演算法比漏桶演算法稍顯複雜。首先,我們有一個固定容量的桶,桶裡存放著令牌(token)。桶一開始是空的,token以 一個固定的速率r往桶裡填充,直到達到桶的容量,多餘的令牌將會被丟
棄。每當一個請求過來時,就會嘗試從桶裡移除一個令牌,如果沒有令牌的話,請求無法通 過。
令牌桶
令牌桶演算法是網路流量整形(Traffic Shaping)和速率限制(Rate Limiting)中最常使用的一種演算法。典型情況下,令牌桶演算法用來控制傳送到網路上的資料的數目,並允許突發資料的傳送(百科)。

在秒殺活動中,使用者的請求速率是不固定的,這裡我們假定為10r/s,令牌按照5個每秒的速率放入令牌桶,桶中最多存放20個令牌。仔細想想,是不是總有那麼一部分請求被丟棄。

計數器 VS 滑動視窗
計數器演算法是最簡單的演算法,可以看成是滑動視窗的低精度實現。滑動視窗由於需要儲存多份的計數器(每一個格子存一份),所以滑動視窗在實現上需要更多的儲存空間。也就是說,如果滑動視窗的精度越高,需要的儲存空間就越大。
漏桶演算法 VS 令牌桶演算法
漏桶演算法和令牌桶演算法最明顯的區別是令牌桶演算法允許流量一定程度的突發。因為預設的令牌桶演算法,取走token是不需要耗費時間的,也就是說,假設桶內有100個token時,那麼可以瞬間允許100個請求通過。
令牌桶演算法由於實現簡單,且允許某些流量的突發,對使用者友好,所以被業界採用地較多。當然我們需要具體情況具體分析,只有最合適的演算法,沒有最優的演算法。