背景
最近了解到很多朋友對限流、熔斷、降級、隔離、超時重試的概念和應用場景理解的不是很到位,所以想用五篇的篇幅稍微系統的介紹一下,
本篇是第一篇,是限流做詳解,如果反饋好的話,我會繼續寫下面四篇,不好的話就算了,算我理解不夠,再自己總結總結,
限流的概念
有朋友問我限流和熔斷有什么區別,我的理解很簡單,限流作用是防御上游流量超過處理能力的手段,熔斷作用是容錯下游的快速失敗手段,
舉個生活中的限流例子:
小A最近打算找個女朋友,他拜托了很多朋友幫自己介紹,朋友們也很給力,很多姑娘都愿意和小A聊一聊,小A發現時間忙不開了,他就制定了一個計劃,一天見2個,這就是限流,
舉個生活中的熔斷例子:
小A在見這些姑娘的時候,如果有的姑娘不守時,超過約定時間半小時還沒有出現,那小A就會離開,不然會耽誤見下一位姑娘,這是一種熔斷手段,另外,如果有的姑娘特別能說,聊天超過了3小時,小A也會打斷姑娘,把姑娘先送走,不然也會耽誤見下一位姑娘,這也是需要的熔斷措施,
限流的原理
不管任何編程語言的實作,目前主流的底層就是基于令牌桶演算法和漏斗演算法,這兩種演算法達到的效果有所不同,
令牌桶演算法
令牌桶演算法是先有個固定容量的桶,一個任務會以固定的速率往桶里放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,有人稱為微服務哨兵,它是一套更完整的生態,除了我上面提到的功能之外,還提供了動態系統保護、熱點限流等功能,

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/3095.html
標籤:架構設計
