大型網站限流演算法的實現和改造

石玉軍發表於2018-09-27

最近寫了一個限流的外掛,所以避免不了的接觸到了一些限流演算法。本篇文章就來分析一下這幾種常見的限流演算法

分析之前

  1. 依我個人的理解來說限流的話應該靈活到可以針對每一個介面來做。比如說一個類裡面有5個介面,那麼我的限流外掛就應該能針對每一個介面就行不同的限流方案。所以呢,既然針對的每個介面所以就需要一個可以唯一標示這個介面的key(我取的是類名+方法名+入參)。

  2. 分散式限流強烈推薦使用redis+lua或者nginx+lua來實現。

  3. 這裡用2個限流條件來做示例講一下常見的限流演算法:

    1. 介面1它10秒鐘最大允許訪問100次

    2. 介面2它10秒鐘最大允許每個人訪問100次。

計數器演算法

這個演算法可以說是限流演算法中最簡單的一種演算法了。

核心思想

計數器演算法的意思呢就是當介面在一個時間單位中被訪問時,我就記下來訪問次數,直到它訪問的次數到達上限。

涉及變數
  1. 介面(key)

  2. 時間單位(expire)

  3. 允許訪問多少次(limit)

  4. 訪問次數(value)

條件一

當一個請求過來時,我們就會得到這個key。


1


2
3
4
5
6
7
8
9


if

(存在

key

){


  value++;
  if (value>= limit ){
  不能訪問
  }
  } else {
  新增 key ,value為 1
      設定 key 過期時間為expire
  }
條件二

既然條件一已經實現了,那條件二會複雜麼 ?

相比於條件一來說就是同一個key對應了多個使用者。那麼我們只需要把key加上使用者的資訊就可以了。比如說 key_使用者1、key_使用者2。

漏桶演算法

核心思想

漏桶演算法的意思呢就是一個介面在一個時間單位中允許被訪問次數是動態變化的(假如一分鐘允許訪問60次,那麼從開始計時時不管有沒有被訪問第59秒只允許訪問59次,30秒只允許30次)。為什麼這樣呢,因為有另外一個執行緒在進行遞減操作

涉及變數
  1. 介面(key)

  2. 時間單位(expire)

  3. 允許訪問多少次(limit)

  4. 遞減間隔時間(interval)

  5. 遞減步長(step)

  6. 剩餘可訪問次數(value)

  7. key的訪問時間(lastUpdateTime)

  8. 當前時間(nowTime)(注意nowTime的取值應為應用取得的時間而不是redis或者nginx取得的時間)

條件一

執行緒一:


1


2
3
4
5
6
7
8


if

(存在key){


  value --;
  if ( value <= ){
  不能訪問
  }
  } else {
  新增key,設定 value 為limit
  }

執行緒二:


1


2
3


while

(過去interval時間){


  所有 key 的value- step
  }
條件二

參考計數器演算法條件二實現。

演算法升級

可以看到實現漏桶演算法的話需要每隔interval時間都要另外一條執行緒去遍歷所key的value去做遞減操作,那麼有沒有什麼辦法可以省略這一步呢。答案是肯定有。


1


2
3
4
5
6
7
8
9
10
11
12
13


if

(存在key){


  value--;
  if ((nowTime-lastUpdateTime)>interval){
  value =value-(nowTime-lastUpdateTime)/interval*step;
      lastUpdateTime =nowTime;
  }
  if (value<=0){
  不能訪問
  }
  } else {
  新增key,設定value為limit;
      lastUpdateTime =nowTime;
  }

令牌桶演算法

核心思想

令牌桶演算法呢,恰恰是和漏桶演算法相反的一個演算法,不過還是推薦你使用這個。這個演算法的原理我不講,我覺得聰明的你看了虛擬碼就明白了。

涉及變數
  1. 介面(key)

  2. 時間單位(expire)

  3. 允許訪問多少次(limit)

  4. 遞增間隔時間(interval)

  5. 遞增步長(step)

  6. 當前可訪問次數(value)

  7. key的訪問時間(lastUpdateTime)

  8. 當前時間(nowTime)(參照漏桶演算法需要注意的點)

條件一

執行緒一:


1


2
3
4
5
6
7
8


if

(存在

key

){


  value++;
  if (value>= limit ){
  不能訪問
  }
  } else {
  新增 key ,設定value為 limit
  }

執行緒二:


1


2
3


while

(過去interval時間){


  所有 key 的value+ step
  }
條件二

參考計算器演算法條件二實現。

演算法升級

參考漏桶演算法升級實現。

程式碼

程式碼實現請參考我的限流框架

本文出自 ,轉載請保留。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31556373/viewspace-2215089/,如需轉載,請註明出處,否則將追究法律責任。

相關文章