穩定性五件套-限流的原理和實現

背景算法

 

最近了解到不少朋友對限流、熔斷、降級、隔離、超時重試的概念和應用場景理解的不是很到位,因此想用五篇的篇幅稍微系統的介紹一下。編程

 

本篇是第一篇,是限流作詳解,若是反饋好的話,我會繼續寫下面四篇。很差的話就算了,算我理解不夠,再本身總結總結。編程語言

 

限流的概念微服務

 

有朋友問我限流和熔斷有什麼區別,個人理解很簡單。限流做用是防護上游流量超過處理能力的手段,熔斷做用是容錯下游的快速失敗手段。工具

 

舉個生活中的限流例子:ui

 

小A最近打算找個女友,他拜託了不少朋友幫本身介紹,朋友們也很給力,不少姑娘都願意和小A聊一聊。小A發現時間忙不開了,他就制定了一個計劃,一天見2個。這就是限流。3d

 

舉個生活中的熔斷例子:對象

 

小A在見這些姑娘的時候,若是有的姑娘不守時,超過約定時間半小時尚未出現,那小A就會離開。否則會耽誤見下一位姑娘,這是一種熔斷手段。另外,若是有的姑娘特別能說,聊天超過了3小時,小A也會打斷姑娘,把姑娘先送走,否則也會耽誤見下一位姑娘。這也是須要的熔斷措施。blog

 

限流的原理token

 

無論任何編程語言的實現,目前主流的底層就是基於令牌桶算法和漏斗算法。這兩種算法達到的效果有所不一樣。

 

令牌桶算法

 

令牌桶算法是先有個固定容量的桶,一個任務會以固定的速率往桶裏放token,請求來了會去取token。若是桶滿了,token就溢出了。多出來的token就不要了。若是請求太快,token生產速度跟不上消費速率,桶空了,有的請求取不到token,這時候就會直接返回錯誤而不繼續處理。

 

舉個例子:

 

好比小A最後找到了心儀的女友小C。他倆相處融洽,一塊兒包餃子吃。小A負責擀皮,小C負責包。小A會把擀好的皮放到一塊案板上。這個案板能夠放20張皮。若是皮擀多了,就放不下,這時候小A就會停下來等。若是皮擀的慢,小C沒的包,也就只能停下來。這裏的皮就至關因而token,包餃子就至關因而處理業務的請求。用圖表示以下:

 

 

 

漏斗算法

 

漏斗算法也是先有個固定容量的桶,請求來了先通過桶,從桶裏出去的速率是必定的。若是請求量讓桶滿了,多出來的請求就不處理了。若是桶是空的,新來的請求就能立刻處理。

 

事實上,各類MQ好比kafka就是典型漏斗算法。broker就是這個固定容量的桶,生產者會不斷的將數據寫到broker裏,消費者是採用的拉取模式,老是以固定的速率來消費。

 

令牌桶算法和漏洞算法的比較

 

限流的實現

 

基礎實現

 

在Java中業界用的比較多的是Google出品的Guava RateLimiter和另外的一款resilience4j-ratelimiter來實現限流。原理差很少。

 

下面以RateLimiter爲例進行講解。要實現一個限流總共須要用到RateLimiter的兩個方法:

 

1>RateLimiter.create() 靜態方法建立對象,初始化桶容量

 

2>acquire()或者tryAcquire()  獲取請求token,二者使用一個便可。acquire方法是阻塞式的,用來實現漏斗算法;tryAcquire是非阻塞式的,用來實現令牌桶算法。

 

阻塞式是若是到達指定條件前一直不返回結果,經過下面的源碼可看到內部其實是用sleep來實現的阻塞。由於全部的請求獲取權限時都會sleep固定的時間才返回,就達到了勻速的目的。

 

非阻塞是當即返回是否獲取到權限(token)。這時候請求若是獲取權限成功就處理請求,獲取權限失敗就直接返回一個自定義的快速失敗處理方式。平時請求速率小於token產生速率,桶漸漸滿了。一旦有突發流量,由於桶裏有存量token,也能夠直接獲取到權限,就是爲何令牌桶算法能夠應對突發流量的原理。

 

高階實現

 

上面實現裏講的是工具組件,若是隻使用工具組件有個問題。限流實際上須要按期進行容量評估,是一個動態的過程,若是隻使用工具組件就須要每次修改代碼。固然也能夠將每一個值寫到一個統一配置裏,好比zookeeper來進行管理。

 

若是規模大的狀況下更好的一個解決方法是使用專門的平臺。這個平臺能夠支撐更多維度的配置,好比集羣維度的限流。集羣維度和單機維度的區別是若是設置了一個總的閾值,系統能夠根據機器資源狀況自動計算出每臺機器的限流狀況。

 

在業界,阿里有個sentinel,有人稱爲微服務哨兵。它是一套更完整的生態,除了我上面提到的功能以外,還提供了動態系統保護、熱點限流等功能。

相關文章
相關標籤/搜索