在上文Sentinel流量防衛兵中講到了Sentinel入門以及流控規則一小部分,而Sentinel還有以下規則:
- 熔斷降級規則
- 熱點引數規則
- 系統規則
- 黑白名單規則
本文要講的是流控規則
流量控制規則
原理
監控應用流量的 QPS 或併發執行緒數等指標,當達到指定的閾值時對流量進行控制,以避免被瞬時的流量高峰沖垮,從而保障應用的高可用性。
QPS限流
這裡我們訪問一下/foo/test
介面,觸發Sentinel控制檯初始化,就可以看到在簇點鏈路
中重新整理出了該介面的資源
然後我們點選+流控
新增流控規則,選擇QPS,並且限流為2
在高階選項中還有流控模式和流控效果兩個選擇,預設為直接和快速失敗,具體含義見下面解釋
新增之後,在頁面上快速點選幾次,就會看到我們之前預設好的限流提示
流控效果
流控效果只針對於QPS的流量控制
快速失敗
當QPS超過任意規則的閾值後,新的請求就會被立即拒絕,拒絕方式為丟擲FlowException
。這種方式適用於對系統處理能力確切已知的情況下,比如通過壓測確定了系統的準確水位時。
案例見上
Warm Up
預熱/冷啟動方式,當系統長期處於低水位的情況下,當流量突然增加時,直接把系統拉昇到高水位可能瞬間把系統壓垮。通過"冷啟動",讓通過的流量緩慢增加,在一定時間內逐漸增加到閾值上限,給冷系統一個預熱的時間,避免冷系統被壓垮。
在控制檯中刪除到剛剛測試的快速失敗
規則,新增一個Warm up
效果的規則
這裡我設定的qps閾值為10,預熱3秒,等效於想要達到10qps,需要預熱3秒。
這裡測試需要用到一些壓測工具,比如我用的是jmeter,畢竟在3秒內每秒連點10下我是做不到,認為自己行的可以自己試試。
以10qps進行壓測之後,可以實時監控中看到這麼一張效果圖
在左邊的線性圖中可以看到通過的qps(綠線)是在勻速上升狀態,直到3秒後達到10變為平穩狀態,具體的數值可以從右邊的表格看到。
排隊等待
排隊等待即為勻速排隊,該方式會嚴格控制請求通過的間隔時間,也即是讓請求以均勻的速度通過,對應的是漏桶演算法。
同樣的,在控制檯新增規則
排隊等待的閾值最高只能配1000哦,至於為什麼小夥伴就自己想啦
以12qps進行壓測,檢視實時監控皮膚
qps一直保持在10, 規則生效了
流控模式
流控模式和呼叫關係有關,呼叫關係包括呼叫方、被呼叫方;一個方法又可能會呼叫其它方法,形成一個呼叫鏈路的層次關係。
直接
根據呼叫來源進行限流,預設為default,即針對所有的來源,這裡面還可以配置自定義的來源。
1.自定義來源
自定義來源需要修改我們的配置程式碼,更改方式如下
private void addSpringMvcInterceptor(InterceptorRegistry registry) {
SentinelWebMvcConfig config = new SentinelWebMvcConfig();
config.setBlockExceptionHandler(new MyBlockExceptionHandler());
// 區分請求方式
config.setHttpMethodSpecify(true);
// 請求來源解析
config.setOriginParser(request -> request.getHeader("User-Agent"));
registry.addInterceptor(new SentinelWebInterceptor(config)).addPathPatterns("/**");
}
在原來的配置中增加來源解析的配置,比如我這裡就是獲取請求頭中的
User-Agent
作為請求來源,你也可以根據自己的需求決定,比如獲取客戶端的ip
修改完畢後,重啟服務,在控制檯新增一個來源為test
的規則
然後在請求上加上User-Agent的header,測試
這裡如果把User-Agent換成其他的,則不會被限流
2. 其他
其他的意思除了指定的來源都會被限流,看到這裡的就會讓人有所疑問
- 控制檯增加了
other
來源的配置,之前的test
來源就不會限流了嗎?
其實它的意思是這樣的:除了test
來源的請求,其他來源的qps都不能超過其他這條配置,舉個例子
test
來源限流的qps為2,other
來源限流的qps為1,那麼此時如果是來自test2
來源的請求,qps超過1則會提示已被限流,test
來源的請求仍舊是超過2之後才會提示被限流。
在控制檯增加一條其他
來源的配置
設定User-Agent
為test2
進行測試
可以看到,我這裡只請求了1次就被限流了
關聯
關聯這個模式指的是如果一個資源被兩個介面所訪問,那麼在一個介面超過qps閾值時,可以對另一個介面進行限流。
舉個例子來說,FooService
同時被A介面和B介面所訪問,由於FooService
總體能夠接受的qps是恆定的,如果A介面qps過高,那麼B介面的就會受到影響,如果我們想要B介面優先,此時我們就可以配置一條當B介面超過qps閾值時,就把A介面限流。
聽起來是不是特別彆扭?, 如果這倆介面有思考能力,我自行腦補出了以下場景:
B介面:我超速了,警察,快把A介面逮捕了,它影響到我超速了。
A介面:???
在程式碼裡面新增一個foo/test2
介面,重啟服務
在控制檯增加配置
以上配置表示:當/foo/test
介面達到qps為10的閾值時,就對/foo/test2
進行限流
測試方式:使用jmeter對/foo/test
介面進行壓測,然後再請求/foo/test2
看看是否被限流了
假裝已經開始對/foo/test
介面進行壓測了,請求/foo/test2
可以看到,這裡隨便請求了一下就返回了限流提示
鏈路
鏈路模式和關聯模式有點像,但是不再是我影響你這種關係了。而指的是如果一個資源被兩個介面所訪問,那麼我們可以指定只對其中某個介面進行限流。
還是那個例子,FooService
同時被A介面和B介面所訪問,此時如果想對UserService
作qps為10的限流,之前的方式就是直接配置一個FooService
qps閾值為10的規則,這樣A,B兩個介面都會被限制訪問,但是如果我只想對A介面的訪問進行限流,B介面的不管,那麼就需要使用鏈路模式了。
但是但是,在目前最新的版本(1.8.2)裡,這個規則不生效!
併發執行緒數
概念
不同於qps,併發執行緒數限定的是某個資源的執行緒數併發上線,用於保護業務執行緒池不被慢呼叫耗盡。
前段時間我的同事就剛好遇上了這樣的問題:
某個介面因為一個bug,執行緒被阻塞了, 導致所有打到這個介面的請求全部陷入阻塞狀態。我們知道tomcat的匯流排程數是有限的,出現這個問題之後的一小會,這個服務的所有執行緒都阻塞在這個介面上了,tomcat執行緒池直接耗盡,所有介面502
如果當時該介面的併發數存在一個閾值,那這個bug所涉及的範圍就可以控制在很小的範圍內了。
演示
新增一個介面,用於模擬執行緒併發情況
public String test3() throws InterruptedException {
// 執行緒停頓1秒,
TimeUnit.SECONDS.sleep(1);
return "ok";
}
重啟服務,訪問/foo/test3
介面觸發初始化
在控制檯新增配置
開啟jmeter進行壓測該介面,然後在其他地方訪問一下(為了好觀察)
規則生效了。
其他的流控模式與qps方式相同,這裡就不演示了
小結
本文介紹了Sentinel的流控規則,其中根據場景分為QPS
限流以及併發執行緒數
限流。
這兩個限流策略的共同點為:可以對來源進行鍼對限流,支援直接
,關聯
,鏈路
三種流控模式。
而QPS
限流還包含了三種流控效果: 快速失敗、預熱、排隊等待。
至於是否叢集
那個選項小夥伴就當沒看到哈,我搞不定這個,我認慫
實在想研究,官方文件在此:https://github.com/alibaba/Sentinel/wiki/叢集流控
本文案例程式碼:https://gitee.com/lzj960515/my-micro-service-demo
追更,想要了解更多精彩內容,歡迎關注公眾號:程式設計師阿鑑
個人部落格空間:https://zijiancode.cn