最近寫了一個限流的插件,所以避免不了的接觸到了一些限流演算法。本篇文章就來分析一下這幾種常見的限流演算法 分析之前 計數器演算法 這個演算法可以說是限流演算法中最簡單的一種演算法了。 計數器演算法的意思呢就是當介面在一個時間單位中被訪問時,我就記下來訪問次數,直到它訪問的次數到達上限。 當一個請求過來時,我們就會 ...
最近寫了一個限流的插件,所以避免不了的接觸到了一些限流演算法。本篇文章就來分析一下這幾種常見的限流演算法
分析之前
- 依我個人的理解來說限流的話應該靈活到可以針對每一個介面來做。比如說一個類裡面有5個介面,那麼我的限流插件就應該能針對每一個介面就行不同的限流方案。所以呢,既然針對的每個介面所以就需要一個可以唯一標示這個介面的key(我取的是類名+方法名+入參)。
- 分散式限流強烈推薦使用redis+lua或者nginx+lua來實現。
- 這裡用2個限流條件來做示例講一下常見的限流演算法:
- 介面1它10秒鐘最大允許訪問100次
- 介面2它10秒鐘最大允許每個人訪問100次。
計數器演算法
這個演算法可以說是限流演算法中最簡單的一種演算法了。
核心思想
計數器演算法的意思呢就是當介面在一個時間單位中被訪問時,我就記下來訪問次數,直到它訪問的次數到達上限。
涉及變數
- 介面(key)
- 時間單位(expire)
- 允許訪問多少次(limit)
- 訪問次數(value)
條件一
當一個請求過來時,我們就會得到這個key。
1
|
if(存在key){
|
條件二
既然條件一已經實現了,那條件二會複雜麽 ?
相比於條件一來說就是同一個key對應了多個用戶。那麼我們只需要把key加上用戶的信息就可以了。比如說 key_用戶1、key_用戶2。
漏桶演算法
核心思想
漏桶演算法的意思呢就是一個介面在一個時間單位中允許被訪問次數是動態變化的(假如一分鐘允許訪問60次,那麼從開始計時時不管有沒有被訪問第59秒只允許訪問59次,30秒只允許30次)。為什麼這樣呢,因為有另外一個線程在進行遞減操作
涉及變數
- 介面(key)
- 時間單位(expire)
- 允許訪問多少次(limit)
- 遞減間隔時間(interval)
- 遞減步長(step)
- 剩餘可訪問次數(value)
- key的訪問時間(lastUpdateTime)
- 當前時間(nowTime)(註意nowTime的取值應為應用取得的時間而不是redis或者nginx取得的時間)
條件一
線程一:
1
|
if(存在key){
|
線程二:
1
|
while(過去interval時間){
|
條件二
參考計數器演算法條件二實現。
演算法升級
可以看到實現漏桶演算法的話需要每隔interval時間都要另外一條線程去遍歷所key的value去做遞減操作,那麼有沒有什麼辦法可以省略這一步呢。答案是肯定有。
1
|
if(存在key){
|
令牌桶演算法
核心思想
令牌桶演算法呢,恰恰是和漏桶演算法相反的一個演算法,不過還是推薦你使用這個。這個演算法的原理我不講,我覺得聰明的你看了偽代碼就明白了。
涉及變數
- 介面(key)
- 時間單位(expire)
- 允許訪問多少次(limit)
- 遞增間隔時間(interval)
- 遞增步長(step)
- 當前可訪問次數(value)
- key的訪問時間(lastUpdateTime)
- 當前時間(nowTime)(參照漏桶演算法需要註意的點)
條件一
線程一:
1
|
if(存在key){
|
線程二:
1
|
while(過去interval時間){
|
條件二
參考計算器演算法條件二實現。
演算法升級
參考漏桶演算法升級實現。
代碼
代碼實現請參考我的限流框架https://github.com/2388386839/syj-ratelimit
本文出自http://zhixiang.org.cn,轉載請保留。