高並發場景下的限流策略

前言

在高併發的場景下,我們的優化和保護系統的方式通常有:多級緩存、資源隔離、熔斷降級、限流等等。

今天我們來聊聊限流。

為什麼需要限流

舉個比較簡單的例子,正常來說,一個員工A他每天能夠處理的工作是10個,突然某一天來了100個工作量,這時候,如果員工A還處理100個,只有一種可能,這個員工被壓垮。

如果我們能預先知道會有100個任務會來,我們通過增加員工數或定義消息隊列等等來臨時解決。

但是我們很多時候無法預料這些意外的。根據墨菲定律,壞事往往會接踵而來,有可能某個點掛了會引起全局的掛掉(雪崩)。因此我們不得不對我們的系統做一些保護措施。限流是其中之一。

針對秒殺這類場景,我們也可以做一些限流措施,而不影響到系統全局。


限流方式之計數器(滑動窗口協議)

思路:限速,我們可能第一個想到的應該是,我通過一個計數器,進行技術,如果超過了計數器閥值,表示速度太快了。一秒一個計數器。

高併發場景下的限流策略

為了便於閱讀,我只截圖了主要的代碼片段。

高併發場景下的限流策略

這樣有個問題就是:粒度太大了,不均勻,針對1秒以下的,沒法辨析。

我們能不能把粒度拆細了,1秒拆成10個100毫秒。每一個100毫秒有一個計數器。瞭解TCP/IP的應該知道,TCP/IP為了增加傳輸速度和控制傳輸速度,有個叫“滑動窗口協議”。

就算拆得再細,也無法解決勻速限制速度的問題。

而且還有個臨界點問題,假如,一秒限制10個請求,在第1秒和第2秒之間,第1秒後半段時間10個請求,第2秒前半段10個請求,那第1秒後半段+第2秒前半段時間組成的一秒鐘裡就有20個請求,沒有起到限速的作用。

有沒有更好的辦法呢?

限速方式之漏桶算法

在生活中,如果一桶有一個細眼,我們往裡面裝水,可以看到水是一滴一滴勻速的下落的,哪我們能不能通過程序來實現這種方式呢。

思路:桶為容器,一滴水為一請求。如果桶滿了就拒絕請求,沒滿處理請求。

高併發場景下的限流策略

代碼片段

高併發場景下的限流策略

在段代碼中

  • 首先計算這次請求與上次請求來的時候,總共漏了多少水。
  • 看一下桶裡面還剩多少水,有沒有溢出。
  • 如果溢出了拒絕請求,如果沒有添加當前一滴水。處理請求。
對於很多應用場景來說,除了要求能夠限制數據的平均傳輸速率外,還要求允許某種程度的突發傳輸。這時候漏桶算法可能就不合適了,令牌桶算法更為適合。

什麼意思呢?就是說我服務前面閒了很久,突然來了很多請求(在桶的容量內),我得快速的把這些處理了。

限速方式之令牌桶算法

思路:勻速的產生令牌,往桶裡面丟,每次請求來,看是否有多餘的令牌。如果有獲取令牌執行正常業務,偌沒有限速。

高併發場景下的限流策略

代碼片段

高併發場景下的限流策略

通過這種方式可以允許瞬時的大量處理,然後做限速處理。

  • 請求來的時候先計算目前放入桶中的令牌數,這裡計算,就可以不用啟動一個線程勻速放置令牌了,這個叫惰性計算。
  • 然後計算桶擁有的令牌數。然後獲取令牌。做拒絕還是處理動作。


單機限速器RateLimiter

安利大家一個高效的限速器。

google的基礎庫guava中包含了一個基於令牌桶的限速器RateLimiter。使用也很簡單。

關注我,私信回覆我“666"或者“Java架構"獲取免費的Java架構學習資料(裡面有高可用、高併發、高性能及分佈式、Jvm性能調優、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!



分享到:


相關文章: