首頁 > 軟體

redis lua限流演演算法實現範例

2022-07-15 14:01:47

限流演演算法

常見的限流演演算法

  • 計數器演演算法
  • 漏桶演演算法
  • 令牌桶演演算法

計數器演演算法

  顧名思義,計數器演演算法是指在一定的時間視窗內允許的固定數量的請求.比如,2s內允許10個請求,30s內允許100個請求等等.如果設定的時間粒度越細,那麼相對而言限流就會越平滑,控制的粒度就會更細.

場景分析

試想,如果設定的粒度比較粗會出現什麼樣的問題呢?如下圖設定一個 1000/3s 的限流計數統計.

圖中的限流策略為3s內允許的最大請求量為1000,那麼會出現2個極端:
 

極端情況1:

  • 第1s請流量為10,  
  • 第2s請流量為10,  
  • 第3s請流量突然激增到980.這意味著在這一刻,有大量的請求蜂擁而至,假設服務每秒能處理的

上線為800/1s,但是此刻卻有超過這個量級的請求量,那麼後果是不堪設想的.

極端情況2:  

  • 第1s請流量突然就達到990,
  • 留給後續第2s,3s的可請求數量就非常少了,可能會出現大量的拒絕請求.

結論:

如果用統計計數演演算法,儘量保持粒度切割精細.

演演算法實現

redis的ttl特性完美的滿足了這一需求,將時間視窗設定為key的失效時間,然後將key的值每次請求+1即可.虛擬碼實現思路:

//1.判斷是否存在該key
if(EXIT(key)){
  // 1.1自增後判斷是否大於最大值,並返回結果
  if(INCR(key) > maxPermit){
     return false;
  }
 return true;
}
//2.不存在key,則設定key初始值為1,失效時間為3秒
SET(KEY,1);
EXPIRE(KEY,3);

漏銅演演算法

漏桶演演算法核心概念:

  • 桶的容量是固定的,並且水流以一個固定的速率流出;
  • 流入的水流可以是任意速率;
  • 如果流入的水流超出了桶的容量,則後續流入的水流溢位(請求被丟棄)。
  • 如果桶內沒有水,則不需要流出

缺點:

不難想象漏桶演演算法並不能很好的應對突發的流量限制,在某一個時間段流量激增,則漏桶演演算法處理就比較無能為力.這個時候就需要用到和他相反設計的令牌桶演演算法

令牌桶演演算法:

如上圖所示,整個請求流程一目瞭然.簡單概括如下:

1.使用者請求資源時首選從桶裡獲取令牌,如果有令牌則放行,如此同時桶裡的令牌數量-1

2.於此同時,以一定的速率往桶裡加入令牌,這個速度是可根據實際場景隨意設定.

演演算法實現

var key;
var maxPermit;//桶的容量,即最大請求限制
var expire;//失效時間
var bucketInterval;//每次向桶裡新增令牌的時間間隔
var bucketNum;//每次向桶裡新增令牌的個數
var lastTimeKey = key +"last";//標記上一次操作時間
//判斷是否存在該key
if(EXIT(key)){
  var value = GET(key);
  var diffTime = now() - lastTimeKey;
  // 1.1判斷是否超出時間間隔
  if(diffTime  > bucketInterval){
      // 1.2根據時間間隔,計算出應該向桶裡新增令牌的個數
      local maxValue = value+math.floor(diff/interval)*step;
      if (maxValue > limit)
         value = limit;
      else
         value = maxValue;
     //設定key的值及操作時間
     SET(key,value);
     SET(lastTimeKey,now());     
  }
  // 2.1在時間間隔內,判斷桶裡是否有值
  if(value <= 0){
     reurn false;
  }else{
    // 2.2 減1
    DECR(key);
  }
reture true;
}
//2.不存在key,則設定key初始值為maxPermit-1
SET(key,maxPermit-1);
EXPIRE(lastTimeKey,now());

上面實現程式碼只是虛擬碼,提供的是一種思路而已. 仔細想來其中某個環節其實並不完美.大家可以參考Guava的ratelimit實現思路,他的限流就是基於令牌桶演演算法,但是比較遺憾的是在單機下的限流.

思考:  

就是時間間隔如果過長的話,一次性向桶裡新增的令牌數量則是桶的最大容量!那麼某個時間的瞬間請求過來,伺服器的壓力是非常大的.

所以此處增加令牌數可以設定的稍微合理些,哪怕間隔時間再長!

以上就是redis lua限流演演算法實現範例的詳細內容,更多關於redis lua限流演演算法的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com