在上文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