1.簡介
限流顧名思義是限制流量,限制流量的目的是為了保障服務穩定執行,避免服務被流量沖垮。當流量超出服務處理能力時,部分請求將會被限流元件攔截。被攔截的請求可能會被丟棄,如果是 C 端請求,那麼這個請求可能會被導向指定的錯誤頁上,而不是生硬的拒絕。這裡我們丟棄掉一部分請求,以保證大部分請求可以正常響應。如果我們不這樣做,那麼服務崩潰後,所有請求都將無法響應了。當一臺機器崩潰後,該機器的所有流量將由其他機器承擔,這樣就會造成剩餘機器壓力增大,進而導致奔潰,最後形成雪崩。除此之外,服務崩潰還會造成資料不一致的嚴重問題,特別是一些敏感資料。比如對於電商網站,如果後臺服務準備將某筆訂單資料存入資料庫時,服務突然崩潰,導致資料沒有落庫。這個時候,開發同學就要想辦法修訂資料了。
綜上,我們可以看出來限流的重要性。接下來,我將向大家介紹三種常用的限流演算法,分別是計數器、漏桶演算法和令牌桶演算法。下面我們從最簡單的計數器開始說起。
2.限流演算法
2.1 計數器
計數器演算法的思想很簡單,每當一個請求到來時,我們就將計數器加一,當計數器數值超過閾值後,就拒絕餘下請求。一秒鐘後,我們將計數器清零,開始新一輪的計數。計數器演算法簡單粗暴,易於實現。但是缺點也是有的,也就是所謂的"突刺現象"。舉例說明一下,假如我們給計數器設定的閾值為100。系統瞬間內(比如10毫秒內)有200個請求到來,這個時候計數器只能放過其中的100個請求,餘下的100個請求全部被拒絕掉。如果第二秒內沒有請求到來,那麼系統就處於空閒狀態。也就是上一秒忙的要死,這一秒又閒的要死。如果我們能用一個容器將剩餘的100個請求快取起來,待計數器重置後再將這些請求放出來。這樣系統在這兩秒內的吞吐量就由100變成了200,提升了一倍。基於這個思考,下面我們再來看看漏桶演算法。
2.2 漏桶演算法
漏桶演算法由流量容器、流量入口和出口組成。其中流量出口流速即為我們期望的限速值,比如 100 QPS。漏桶演算法除了具備限流能力,還具備流量整型功能。下面我們通過一張圖來了解漏桶演算法。
圖片來源:未知
如上圖,流入漏桶流量的流速是不恆定的,經過漏桶限速後,流出流量的速度是恆定的。需要說明的是,漏桶的容量是有限的,一旦流入流量超出漏桶容量,這部分流量只能被丟棄了。
漏桶是一個比較好的限流整型工具,不過漏桶不能處理突發流量,一些觀點認為這是它的一個缺點。不過如果較起真來,我覺得這個缺點是不成立的。畢竟漏桶本就是用來平滑流量的,如果支援突發,那麼輸出流量反而不平滑了。如果要找一種能夠支援突發流量的限流演算法,那麼令牌桶演算法可以滿足需求。
2.3 令牌桶演算法
令牌桶和漏桶頗有幾分相似,只不過令牌通裡存放的是令牌。它的執行過程是這樣的,一個令牌工廠按照設定值定期向令牌桶發放令牌。當令牌桶滿了後,多出的令牌會被丟棄掉。每當一個請求到來時,該請求對應的執行緒會從令牌桶中取令牌。初期由於令牌桶中存放了很多個令牌,因此允許多個請求同時取令牌。當桶中沒有令牌後,無法獲取到令牌的請求可以丟棄,或者重試。下面我們來看一下的令牌桶示意圖:
圖片來源:未知
儘管令牌桶允許突發流量,但突發流量速率 R1 + 限流速率 R2 不能超過系統最大的處理能力 Rt,即 R1 + R2 ≤ Rt,否則會沖垮系統。
3.總結
以上就是本篇文章的全部內容。本篇文章簡單分析幾種常見限流演算法的執行過程,限於能力原因,文章若有錯誤不妥之處還請指明。除了文字性描述,這裡也把三種演算法的簡單實現程式碼貼出來 RateLimiter,有興趣的同學自取。
好了,本篇文章到這裡就結束了,感謝大家的閱讀。
本文在知識共享許可協議 4.0 下發布,轉載需在明顯位置處註明出處
作者:田小波
本文同步釋出在我的個人部落格:http://www.tianxiaobo.com
本作品採用知識共享署名-非商業性使用-禁止演繹 4.0 國際許可協議進行許可。