限流演算法介紹

johnychen發表於2021-09-09

高併發的處理有三個比較常用的手段,快取,限流和降級。快取的使用相信很多開發者都很瞭解了,諸如redis,memcache等工具都會活躍在我們的系統當中。但是假如在某一時間段內出現了遠超預想的流量訪問到系統,例如在搞秒殺活動之類的,這樣一來我們應該如何保護業務系統呢?

在參加一些秒殺活動的時候,我們可以看到,有時候會有 系統繁忙,請稍後再試
或者 請稍等 的提示,那這個系統就很可能是使用了限流的手段。

限流是限制系統的輸入和輸出流量,以達到保護系統的目的。而限流的實現主要是依靠限流演算法,限流演算法主要有4種:
1、固定時間視窗(計數器);
2、滑動時間視窗;
3、令牌桶演算法;
4、漏桶演算法;

1、計數器

計數器就是統計記錄單位時間內進入系統或者某一介面的請求次數,在限定的次數內的請求則正常接收處理,超過次數的請求則拒絕掉,或者改為非同步處理。


圖片描述

image.png

假設我們設定單位時間內進入系統的的最大請求數為100,如果有超過100個請求集中在重新整理計數器的臨界點前後進入系統,而且單位時間的粒度比較粗的話,那就容易誤傷很多正常請求。

    // 演算法虛擬碼
    ++counter;    if(counter > limit) {        return '系統繁忙,請稍後再試';
     }
2、滑動時間視窗

這個名稱要跟TCP的視窗滑動區分開來,但是理解之後會發現其實也是有點相似。
計數器演算法對流量的限制比較粗放,而滑動時間視窗的演算法則是對流量進行更加平穩的控制。上面的計數器的單位時間是1分鐘,而在使用滑動時間視窗,可以把1分鐘分成6格,每格時間長度是10s,每一格又各自管理一個計數器,單位時間用一個長度為60s的視窗描述。一個請求進入系統,對應的時間格子的計數器便會+1,而每過10s,這個視窗便會向右滑動一格。只要視窗包括的所有格子的計數器總和超過限流上限,便會拒絕後面的請求。


圖片描述

image.png

      // 演算法虛擬碼
      var cellIndex = time % cellNum;
      ++cellCounter[cellIndex];      var sum = 0;      for(var i = cellIndex; i >= cellIndex - cellNum; --i) {
          sum += cellCounter[i];
      }      if(sum > limit) {            return '系統繁忙,請稍後再試';
      }
3、漏桶演算法

漏桶演算法,又稱leaky bucket。下圖是wiki上的漏桶圖解:


圖片描述

image.png


一個系統處理請求,就像一個固定容量的水桶去溜進來的水,同時也讓水流出去,但是它無法預見有多少水流進來和水流進來的速度,它只能夠控制從桶底水流出去的速度,多出來的水,就只好讓它從桶邊流出去了。這個從桶底流出去的水就是系統正常處理的請求,從旁邊流出去的水就是系統拒絕掉的請求。如此一來,我們只要監控系統單位時間內處理請求的速率就可以了,速率超過上限後的請求都給拒絕掉就可以了。

      // 演算法虛擬碼
      ++counter;      var time = nowTime - (nowTime % interval);      var rate = counter / time;      if(rate> limitRate) {            return '系統繁忙,請稍後再試';
      }
4、令牌桶演算法

繼續wiki圖解。


圖片描述

image.png


令牌桶即是以一定速率生成token並放入桶中,請求進入系統需要先拿到token才能進行業務處理,無token的請求則拒絕掉。令牌桶演算法實際上跟漏桶演算法很相似,而實際使用中其實也不需要另起執行緒生成token,只需要把握好token生成速率和當前應該剩餘的token數量即可。

在時間點重新整理的臨界點上,只要剩餘token足夠,令牌桶演算法會允許對應數量的請求透過,而後重新整理時間因為token不足,流量也會被限制在外,這樣就比較好的控制了瞬時流量。因此,令牌桶演算法也被廣泛使用。



作者:菜six歲
連結:

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

相關文章