服務限流原理及算法

限流是啥?
維基百科是這樣解釋的:
在計算機網絡中,頻率限制被應用在控制網絡接口收到或發送的請求頻次,它可以被用來阻止dos攻擊或者是網絡爬蟲。
直白點說,就是限制服務收到或發出的請求頻次,保證整體服務可以正常健康的使用。
談到這裏有人會想,只要我服務處理的速度足夠快,那麼頻次高點也沒問題,而且我們做的系統不就應該接受各種峯值考驗麼?
這麼想沒問題,提高服務的吞吐量確實是沒問題,但是有時出於安全角度考慮,比如爬蟲,就不應該讓他過快的獲取到抓取的數據,還可能涉及到洗錢網絡安全什麼的。
另外一方面,需求的開發是有成本的,不應該想當然,在超出系統本來承受打範圍後,還有數量級差異的請求進來,這種需求改進的成本無論是人工還是費用都是巨大的。
因此限流是肯定有存在必要的。下面我們來談談經典的限流都有哪些:
假設我們要實現1分鐘,100次的限流:
1、計數器限流(固定窗口限流)
這個算法簡單實用,基本可以滿足很多業務場景的需要
大致原理是這樣的,有一個全局的計數器,初始值爲0,每次請求進來,計數器+1,然後再處理,如果計數器超過100,則不再處理請求,直接返回。
同時我們啓動一個定時的線程,每過1分鐘,就重置計數器爲0;
流程大概是下邊這個樣子:

但是這種計數器限流有一個臨界的問題,我們初衷其實上是,任意的一分鐘範圍內,處理的請求不超過100。
但是假若第一分鐘最後10s處理100個請求,第二分鐘最初10s處理100個請求,也就是說20s內,我們共處理了200請求,這顯然是不滿足最初我們的訴求的。
2、滑動窗口
爲了解決傳統計數器限流的弊端,有人提出了滑動窗口的概念。所謂的滑動窗口,是指不存在固定的起止、結束的時間點。而是當前的時間點向前推動單位週期,判定流量是否超限:(防盜連接:本文首發自http://www.cnblogs.com/jilodream/ )
舉個例子,比如1min,100次的限流
我們將時間劃分成10s每個單位
請求如下圖,在窗口1期間,請求已經到達60次,因此後兩個時間單位內就進入限流狀態。

但是隨着時間推移,窗口2期間的請求次數再次小於了100,又可以處理請求。
繼續推移,窗口3的請求次數再次到達100,因此又被限流。

滑動窗口如何實現呢?
我們可以使用一個HashMap或者乾脆使用一個數組,然後統計每個時間單位內的請求,當判斷是否限流時,只要統計時間窗內的請求次數是否滿足即可。
同時map或者是數組我們並不需要無限大,我們可以反覆利用其中已經過期的位置。另外滑動窗口的單位時間越小,整體的限流也就會越精準。

3、漏桶算法
滑動窗口的結尾我們有說時間單位越小,那麼就越精準平滑,可是我們並不能把時間單位搞到無限小,或者說盡可能小的時候就出現偏差,比如1ns,但是可能你剛計算完限流後,已經到下一個時間單位了
爲了解決這種問題,有人提出了漏桶算法。
如圖,這個模型和消息隊列有點像:


請求進來後,會先放置在漏桶中,漏桶最多保存的請求是有限的。當漏桶滿了以後,會丟棄請求,否則會添加到漏桶的隊尾。
同時任務處理會恆定的處理漏桶隊列中的請求。以此達到平衡。漏桶算法也並不一定需要一個列隊,我們也可以使用一個計數器,當請求進來後,計數器+1。計數器滿了以後會請求丟棄。同時任務處理完畢後會回調計數器-1;(防盜連接:本文首發自http://www.cnblogs.com/jilodream/ )

4、令牌桶算法
漏桶算法會讓請求更加平滑,但是當有突發請求衝擊時,並且我們的下游處理速度又比較快(或者是使用固定頻率)來處理,這樣我們沒有辦法很好的控制請求的處理速率。
如果你設置固定頻率,當某個時段請求衝擊比較大,而我們也應該滿足時,顯然無法滿足。當放開請求頻率,又可能因爲下游處理速度太快,對機器的整體性能造成衝擊,而且我們又無法控制。
針對這種情況,有人提供了令牌桶算法:
如圖

1、有線程會按照固定頻率向令牌桶中添加令牌,當令牌桶滿了之後,就不會繼續添加。
2、請求來了之後,向令牌桶中請求令牌,成功拿到令牌可以繼續處理請求
3、未請求到令牌,則丟棄該請求

不知道大家有沒有是否記得有一款騰訊的小遊戲叫開心消消樂。其中的防沉迷策略就是通過令牌桶的算法處理的。玩家每次玩遊戲會消耗一份閃電(令牌),可以連續玩,直到所有閃電都消耗完畢。
同時隨着時間的推移,閃電又會慢慢變滿,但是最多不會超過上限(令牌桶滿)。在這個增加的過程中,我們也可以同時去玩消消樂消耗令牌

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章