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...