服務治理 限流(令牌桶演算法)

2022-09-07 00:39:15 字數 4044 閱讀 8061

1、最近在寫乙個分布式服務的框架,對於分布式服務的框架來說,除了遠端呼叫,還要進行服務的治理

當進行**的時候,所有的資源都用來完成重要的業務,就比如雙11的時候,主要的業務就是讓使用者查詢商品,以及購買支付,

此時,金幣查詢、積分查詢等業務就是次要的,因此要對這些服務進行服務的降級,典型的服務降級演算法是採用令牌桶演算法,

因此在寫框架的時候去研究了一下令牌桶演算法

2、在實施qos策略時,可以將使用者的資料限制在特定的頻寬,當使用者的流量超過額定頻寬時,超過的頻寬將採取其它方式來處理。

要衡量流量是否超過額定的頻寬,網路裝置並不是採用單純的數字加減法來決定的,也就是說,比如頻寬為100k,而使用者發來

的流量為110k,網路裝置並不是靠110k減去100k等於10k,就認為使用者超過流量10k。網路裝置衡量流量是否超過額定頻寬,

需要使用令牌桶演算法來計算。下面詳細介紹令牌桶演算法機制:

當網路裝置衡量流量是否超過額定頻寬時,需要檢視令牌桶,而令牌桶中會放置一定數量的令牌,乙個令牌允許介面傳送

或接收1bit資料(有時是1 byte資料),當介面通過1bit資料後,同時也要從桶中移除乙個令牌。當桶裡沒有令牌的時候,任何流

量都被視為超過額定頻寬,只有當桶中有令牌時,資料才可以通過介面。令牌桶中的令牌不僅僅可以被移除,同樣也可以往裡新增,

所以為了保證介面隨時有資料通過,就必須不停地往桶裡加令牌,由此可見,往桶裡加令牌的速度,就決定了資料通過介面的速度。

因此,我們通過控制往令牌桶裡加令牌的速度從而控制使用者流量的頻寬。而設定的這個使用者傳輸資料的速率被稱為承諾資訊速率(cir),

通常以秒為單位。比如我們設定使用者的頻寬為1000  bit每秒,只要保證每秒鐘往桶裡新增1000個令牌即可。

3、舉例:

將cir設定為8000  bit/s,那麼就必須每秒將8000個令牌放入桶中,當介面有資料通過時,就從桶中移除相應的令牌,每通過1  bit,

就從桶中移除1個令牌。當桶裡沒有令牌的時候,任何流量都被視為超出額定頻寬,而超出的流量就要採取額外動作。每秒鐘往桶裡加的令牌

就決定了使用者流量的速率,這個速率就是cir,但是每秒鐘需要往桶裡加的令牌總數,並不是一次性加完的,一次性加進的令牌數量被稱為burst  size(bc),

如果bc只是cir的一半,那麼很明顯每秒鐘就需要往桶裡加兩次令牌,每次加的數量總是bc的數量。還有就是加令牌的時間,time interval(tc),

tc表示多久該往桶裡加一次令牌,而這個時間並不能手工設定,因為這個時間可以靠cir和bc的關係計算得到,  bc/ cir= tc。

4、令牌桶演算法圖例

a. 按特定的速率向令牌桶投放令牌

b. 根據預設的匹配規則先對報文進行分類,不符合匹配規則的報文不需要經過令牌桶的處理,直接傳送;

c. 符合匹配規則的報文,則需要令牌桶進行處理。當桶中有足夠的令牌則報文可以被繼續傳送下去,同時令牌桶中的令牌 量按報文的長度做相應的減少;

d. 當令牌桶中的令牌不足時,報文將不能被傳送,只有等到桶中生成了新的令牌,報文才可以傳送。這就可以限制報文的流量只能是小於等於令牌生成的速度,達到限制流量的目的。

package

com.netease.datastream.util.flowcontrol;

import

j**a.io.bufferedwriter;

import

j**a.io.fileoutputstream;

import

j**a.io.ioexception;

import

j**a.io.outputstreamwriter;

import

j**a.util.random;

import

j**a.util.concurrent.arrayblockingqueue;

import

j**a.util.concurrent.executors;

import

j**a.util.concurrent.scheduledexecutorservice;

import

j**a.util.concurrent.timeunit;

import

j**a.util.concurrent.locks.reentrantlock;

/**** created by inter12 on 15-3-18.

*

*/

public

class

tokenbucket

public tokenbucket(int maxflowrate, int

**gflowrate)

public tokenbucket(int everytokensize, int maxflowrate, int

**gflowrate)

public

void

addtokens(integer tokennum)

}public

tokenbucket build()

/*** 獲取足夠的令牌個數

* *

@return

*/public

boolean gettokens(byte

datasize)

int tokencount = 0;

for (int i = 0; i < needtokennum; i++)

}return tokencount ==needtokennum;

} finally

}public

void

start()

//初始化令牌生產者

tokenproducer tokenproducer = new tokenproducer(**gflowrate, this

); scheduledexecutorservice.scheduleatfixedrate(tokenproducer, 0, 1,

timeunit.seconds);

isstart = true

; }

public

void

stop()

public

boolean

isstarted()

class tokenproducer implements

runnable

@override

public

void

run()

}public

static

tokenbucket newbuilder()

public tokenbucket everytokensize(int

everytokensize)

public tokenbucket maxflowrate(int

maxflowrate)

public tokenbucket **gflowrate(int

**gflowrate)

private string stringcopy(string data, int

copynum)

return

sbuilder.tostring();

}public

static

void main(string args) throws

ioexception,

interruptedexception

private

static

void

arraytest()

private

static

void tokentest() throws

interruptedexception, ioexception

else

bufferedwriter.newline();

bufferedwriter.flush();

}bufferedwriter.close();}}

springgateway限流 令牌桶演算法

參見 lua指令碼 參見spring spring cloud gateway core包下的request rate limiter.lua redis從2.6版本開始引入對lua指令碼的支援,通過在伺服器中嵌入lua環境,redis客戶端可以使用lua指令碼,直接在伺服器端原子地執行多個redi...

redis令牌桶限流

每個ip 1秒內只能傳送一次請求 pom檔案 org.springframework.bootgroupid spring boot starter data redis reactiveartifactid 2.1.3.releaseversion dependency 啟動引導類定義 keyre...

php令牌桶限流

前端每次請求從令牌桶取走令牌,後端勻速向桶內投遞令牌,如果前端取到令牌,則說明這次請求有效,否則讓前端再次請求或者等待。避免了大量請求下伺服器壓力過大導致的崩潰問題。令牌桶演算法 class token catch redi ception exception 令牌初始化 public functi...