分布式限流實戰 redis實現令牌桶限流

2021-10-08 19:29:05 字數 2965 閱讀 4068

這篇文章我們主要是分析一下分布式限流的玩法。 因為限流也是乙個經典用法了。

隨著微服務的流行,服務和服務之間的穩定性變得越來越重要。快取、降級和限流是保護微服務系統執行穩定性的三大利器。

快取的目的是提公升系統訪問速度和增大系統能處理的容量,而降級是當服務出問題或者影響到核心流程的效能則需要暫時遮蔽掉,待高峰或者問題解決後再開啟,而有些場景並不能用快取和降級來解決,比如稀缺資源、資料庫的寫操作、頻繁的複雜查詢,因此需有一種手段來限制這些場景的請求量,即限流。

比如當我們設計了乙個函式,準備上線,這時候這個函式會消耗一些資源,處理上限是1秒服務3000個qps,但如果實際情況遇到高於3000的qps該如何解決呢?

所以限流的目的應當是通過對併發訪問/請求進行限速或者乙個時間視窗內的的請求進行限速來保護系統,一旦達到限制速率就可以拒絕服務、等待、降級。

學習如何去實現乙個分布式限流框架,首先,我們需要去了解最基本的兩種限流演算法。

微服務架構下的分布式限流方案全解析

令牌桶演算法和漏桶演算法效果一樣但方向相反的演算法,更加容易理解。隨著時間流逝,系統會按恆定1/qps時間間隔(如果qps=100,則間隔是10ms)往桶裡加入令牌(想象和漏洞漏水相反,有個水龍頭在不斷的加水),如果桶已經滿了就不再加了。新請求來臨時,會各自拿走乙個令牌,如果沒有令牌可拿了就阻塞或者拒絕服務。示意圖(**網路)如下:

微服務架構下的分布式限流方案全解析

漏桶演算法與令牌桶演算法的區別在於,漏桶演算法能夠強行限制資料的傳輸速率,令牌桶演算法能夠在限制資料的平均傳輸速率的同時還允許某種程度的突發情況。令牌桶還有乙個好處是可以方便的改變速度。一旦需要提高速率,則按需提高放入桶中的令牌的速率。所以,限流框架的核心演算法還是以令牌桶演算法為主。

已知上面講述的令牌桶演算法的原理,如何通過**實現?

本地限流的實現可以用long長整型作為令牌桶,為了達到無鎖,建議使用long的原子型別atomiclong,使用atomiclong的好處就是可以非常方便的對其進行cas加操作與cas減操作(也就是令牌桶令牌的放入與拿取),以避免執行緒的上下文切換的開銷,核心cas演算法如下:

private

boolean

tryacquirefailed()

l = bucket.

lon**alue()

;}return

false

;}

根據上述了解的令牌桶演算法可以得知,令牌桶需要乙個scheduledthread不斷的放入令牌,這部分的**如下:

scheduledthreadexecutor.

scheduleatfixedrate((

)->

bucket.

set(rule.

getlimit()

), rule.

getinitialdelay()

, rule.

getperiod()

, rule.

getunit()

);

分布式限流需要解決什麼問題呢?我想至少有下面幾個:

1.動態規則:比如限流的qps我們希望可以動態修改,限流的功能可以隨時開啟、關閉,限流的規則可以跟隨業務進行動態變更等。

2.集群限流:比如對spring cloud微服務架構中的某服務下的所有例項進行統一限流,以控制後續訪問資料庫的流量。

3.熔斷降級:比如在呼叫鏈路中某個資源出現不穩定狀態時(例如呼叫超時或異常比例公升高),對這個資源的呼叫進行限制,讓請求快速失敗,避免影響到其它的資源而導致級聯錯誤。

可選的其它幾個功能,諸如實時監控資料、閘道器流控、熱點引數限流、系統自適應限流、黑白名單控制、註解支援等,這些功能其實可以非常方便的進行擴充套件。

這裡就直接帖一下**就好了

/**

* 令牌桶演算法限流

* @author 田培融

*/@slf4j

@component

public class redisraterlimiter

// maxcount為主要判斷標誌

string maxcount = redistemplate.opsforvalue(

).get(maxcountkey)

; string currcount = redistemplate.opsforvalue(

).get(currcountkey)

; // 初始

if(strutil.isblank(maxcount))

else

if(strutil.isnotblank(maxcount)

&&strutil.isnotblank(currcount))

}else

} catch (exception e)

return null;

}}

第乙個引數只要不重複就行,隨便寫。 主要是為了區別要限制什麼。 第二個引數是表示限制訪問的次數。第三個引數是表示多長時間內限制訪問的次數。

使用案例:

string token = redisraterlimiter.

acquiretoken

("upload:"

+ipinfoutil.

getipaddr

(request),1

,300000l);if

(strutil.

isblank

(token)

)

好了,這就是我們專案中的分布式限流了。

交個朋友吧。

分布式限流實戰

由於api介面無法控制呼叫方的行為,因此當遇到瞬時請求量激增時,會導致介面占用過多伺服器資源,使得其他請求響應速度降低或是超時,更有甚者可能導致伺服器宕機。限流 rate limiting 指對應用服務的請求進行限制,例如某一介面的請求限制為100個每秒,對超過限制的請求則進行快速失敗或丟棄。限流可...

基於Redis的分布式服務限流

基於redis快取的分布式服務限流 1 定於限流註解,限流註解可以加需要限流的業務類上,value為限流業務型別 target elementtype.method retention retentionpolicy.runtime public inte ce tpscontrol2 限流配置類,...

redis lua分布式限流

註解反思 我們專案有好幾個介面,呼叫公司中颱的介面,包括定時器的分片執行還有本人的多執行緒強行壓榨,哈哈。最後加上使用者的瘋狂請求,導致中颱的介面偶爾出現問題,主要是資料庫cpu達到100 昨晚專門做了個限流,那麼技術定型使用什麼呢?ratelimiter?這好像是單機才能玩,sentinel?這個...