#頭條創作挑戰賽#
終身學習、樂于分享、共同成長!
前言
在上一章中學習了使用代碼來實作Sentinel的相關流控規則配置,在生産環境中我們實際都會使用Sentinel提供的控制台來進行流控、降級規則的設定,在本章中我們來了解Sentinel控制台的詳細規則配置。
在sentinel控制台中設定流控規則:
- 資源名: 接口的API
- 針對來源: 預設是default,當多個微服務都調用這個資源時,可以配置微服務名來對指定的微服務設定門檻值
- 門檻值類型: 分為QPS和線程數 假設門檻值為10
- QPS類型: 隻得是每秒通路接口的次數>10就進行限流
- 線程數: 為接受請求該資源配置設定的線程數>10就進行限流
微服務和Sentinel Dashboard通信原理
Sentinel控制台與微服務端之間,實作了一套服務發現機制,內建了Sentinel的微服務都會将中繼資料傳遞給Sentinel控制台,架構圖如下所示:
注:流控針對服務提供者,熔斷降級針對服務消費者
Sentinel控制台功能介紹
在上一章中部署啟動Sentinel的方式是通過原生方式來啟動,原生方式需要配置比較多的參數,在本章中我們來使用Docker鏡像的方式來啟動,使用Docker方式可以更快地擷取Sentinel控制台,并且免去了環境配置問題。
- 拉取Sentinel鏡像
docker pull bladex/sentinel-dashboard
- 啟動容器
docker run -d --name sentinel -p 8089:8089 bladex/sentinel-dashboard
1.實時監控
Sentinel控制台的首頁展示了各個應用的概況,包括QPS、RT、線程池等關鍵名額的實時資料。通過首頁可以友善地定位出現異常的服務或者熔斷降級的接口。
我們啟動上一章的demo通路對應的擷取使用者資訊模拟接口,檢視Sentinel首頁:
2.簇點鍊路
簇點鍊路功能可以顯示應用程式之間的調用關系,幫助開發人員快速定位問題發生的位置。
3.流控規則
流控規則用于限制應用程式通路某些資源的速率,避免因過高的通路頻率導緻資源耗盡。在Sentinel控制台中,可以添加、編輯、删除流控規則。
其原理是監控應用流量的QPS或并發線程數等名額,當達到指定的門檻值時對流量進行控制,以避免被瞬時的流量高峰沖垮,進而保障應用的高可用性。
同一個資源可以建立多條限流規則。FlowSlot 會對該資源的所有限流規則依次周遊,直到有規則觸發限流或者所有規則周遊完畢。
一條限流規則主要由下面幾個因素組成,我們可以組合這些元素來實作不同的限流效果:
Field | 說明 | 預設值 |
resource | 資源名,即限流規則的作用對象 | |
count | 限流門檻值 | |
grade | 限流門檻值類型(QPS 或并發線程數) | QPS |
limitApp | 流控針對的調用來源,若為default則不區分調用來源 | default |
strategy | 調用關系限流政策:直接、鍊路、關聯 | 根據資源本身(直接) |
controlBehavior | 流量控制效果(直接拒絕、Warm Up、勻速排隊) | 直接拒絕 |
count | 是否叢集限流 | 否 |
官網參考文檔:
https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6
接下來我們建立一個流控規則:
限流門檻值類型
QPS
QPS(Query Per Second)每秒請求數,就是說伺服器在一秒的時間内處理了多少個請求。
QPS設定為1則表示1秒内隻處理一個請求,當1秒内請求數大于1時就限流。
QPS限流門檻值設定為1,其他的設定都是預設配置。
測試:
這裡我們可以看到被流控後傳回的是Sentinel自定義的異常資訊,通常在實際應用中都需要自定義傳回異常資訊,這時候可以自定義BlockExceptionHandler的實作類統一處理BlockException。
/**
* @author Seven
* @description
* @Gitee https://gitee.com/it-codelab
* @Copyright 公衆号:Seven的代碼實驗室
*/
@Slf4j
@Component
public class SentinelBlockExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
R r = null;
if (e instanceof FlowException) {
r = new R(5001, "接口限流了");
} else if (e instanceof DegradeException) {
r = new R(5002, "服務降級了");
} else if (e instanceof ParamFlowException) {
r = new R(5003, "熱點參數限流了");
} else if (e instanceof SystemBlockException) {
r = new R(5001, "觸發系統保護規則了");
} else if (e instanceof AuthorityException) {
r = new R(5001, "授權規則不通過");
}
// 傳回錯誤資訊
response.setStatus(500);
response.setCharacterEncoding("UTF-8");
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
new ObjectMapper().writeValue(response.getWriter(), r);
}
}
并發線程數
并發數控制用于保護業務線程池不被慢調用耗盡。例如,當應用所依賴的下遊應用由于某種原因導緻服務不穩定、響應延遲增加,對于調用者來說,意味着吞吐量下降和更多的線程數占用,極端情況下甚至導緻線程池耗盡。為應對太多線程占用的情況,業内有使用隔離的方案,比如通過不同業務邏輯使用不同線程池來隔離業務自身之間的資源争搶(線程池隔離)。
這種隔離方案雖然隔離性比較好,但是代價就是線程數目太多,線程上下文切換的 overhead 比較大,特别是對低延時的調用有比較大的影響。Sentinel 并發控制不負責建立和管理線程池,而是簡單統計目前請求上下文的線程數目(正在執行的調用數目),如果超出門檻值,新的請求會被立即拒絕,效果類似于信号量隔離。并發數控制通常在調用端進行配置。
這裡提供兩種測試驗證方式:
- 官網提供的源碼測試:
https://github.com/alibaba/Sentinel/blob/master/sentinel-demo/sentinel-demo-basic/src/main/java/com/alibaba/csp/sentinel/demo/flow/FlowThreadDemo.java
- 利用jmeter測試
流控模式
基于調用關系的流量控制。調用關系包括調用方、被調用方;一個方法可能會調用其它方法,形成一個調用鍊路的層次關系。
直接
資源調用達到設定的門檻值後直接被流控抛出異常。
關聯
當兩個資源之間具有資源争搶或者依賴關系的時候,這兩個資源便具有了關聯。比如對資料庫同一個字段的讀操作和寫操作存在争搶,讀的速度過高會影響寫得速度,寫的速度過高會影響讀的速度。如果放任讀寫操作争搶資源,則争搶本身帶來的開銷會降低整體的吞吐量。可使用關聯限流來避免具有關聯關系的資源之間過度的争搶,舉例來說,read_db和write_db這兩個資源分别代表資料庫讀寫,我們可以給read_db設定限流規則來達到寫優先的目的:設定strategy 為
RuleConstant.STRATEGY_RELATE同時設定refResource為write_db。這樣當寫庫操作過于頻繁時,讀資料的請求會被限流。
鍊路
NodeSelectorSlot 中記錄了資源之間的調用鍊路,這些資源通過調用關系,互相之間構成一棵調用樹。這棵樹的根節點是一個名字為 machine-root 的虛拟節點,調用鍊的入口都是這個虛節點的子節點。
一棵典型的調用樹如下圖所示:
machine-root
/ \
/ \
Entrance1 Entrance2
/ \
/ \
DefaultNode(nodeA) DefaultNode(nodeA)
上圖中來自入口 Entrance1 和 Entrance2 的請求都調用到了資源 NodeA,Sentinel 允許隻根據某個入口的統計資訊對資源限流。比如我們可以設定 strategy 為
RuleConstant.STRATEGY_CHAIN,同時設定 refResource 為 Entrance1 來表示隻有從入口 Entrance1 的調用才會記錄到 NodeA 的限流統計當中,而不關心經 Entrance2 到來的調用。
流控效果
快速失敗
快速失敗(
RuleConstant.CONTROL_BEHAVIOR_DEFAULT)方式是預設的流量控制方式,當QPS超過任意規則的門檻值後,新的請求就會被立即拒絕,拒絕方式為抛出FlowException。這種方式适用于對系統處理能力确切已知的情況下,比如通過壓測确定了系統的準确水位時。
Warm Up
Warm Up(
RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即預熱/冷啟動方式。當系統長期處于低水位的情況下,當流量突然增加時,直接把系統拉升到高水位可能瞬間把系統壓垮。通過"冷啟動",讓通過的流量緩慢增加,在一定時間内逐漸增加到門檻值上限,給冷系統一個預熱的時間,避免冷系統被壓垮。
冷加載因子: codeFactor 預設是3,即請求 QPS 從 threshold / 3 開始,經預熱時長逐漸升至設定的 QPS 門檻值。
通常冷啟動的過程系統允許通過的 QPS 曲線如下圖所示:
勻速排隊
勻速排隊(
RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式會嚴格控制請求通過的間隔時間,也即是讓請求以均勻的速度通過,對應的是漏桶算法。
該方式的作用如下圖所示:
這種方式主要用于處理間隔性突發的流量,例如消息隊列。想象一下這樣的場景,在某一秒有大量的請求到來,而接下來的幾秒則處于空閑狀态,我們希望系統能夠在接下來的空閑期間逐漸處理這些請求,而不是在第一秒直接拒絕多餘的請求。
注意:勻速排隊模式暫時不支援 QPS > 1000 的場景。
4.降級規則
降級規則用于對某些服務進行自動熔斷處理,當服務達到設定的門檻值時,自動觸發降級政策。在Sentinel控制台中,可以添加、編輯、删除降級規則。
一個服務常常會調用别的子產品,可能是另外的一個遠端服務、資料庫,或者第三方 API 等。例如,支付的時候,可能需要遠端調用銀聯提供的 API;查詢某個商品的價格,可能需要進行資料庫查詢。然而,這個被依賴服務的穩定性是不能保證的。如果依賴的服務出現了不穩定的情況,請求的響應時間變長,那麼調用服務的方法的響應時間也會變長,線程會産生堆積,最終可能耗盡業務自身的線程池,服務本身也變得不可用。
現代微服務架構都是分布式的,由非常多的服務組成。不同服務之間互相調用,組成複雜的調用鍊路。以上的問題在鍊路調用中會産生放大的效果。複雜鍊路上的某一環不穩定,就可能會層層級聯,最終導緻整個鍊路都不可用。是以我們需要對不穩定的弱依賴服務調用進行熔斷降級,暫時切斷不穩定調用,避免局部不穩定因素導緻整體的雪崩。熔斷降級作為保護自身的手段,通常在用戶端(調用端)進行配置。
熔斷降級規則(DegradeRule)包含下面幾個重要的屬性:
Field | 說明 | 預設值 |
resource | 資源名,即規則的作用對象 | |
grade | 熔斷政策,支援慢調用比例/異常比例/異常數政策 | 慢調用比例 |
count | 慢調用比例模式下為慢調用臨界 RT(超出該值計為慢調用);異常比例/異常數模式下為對應的門檻值 | |
timeWindow | 熔斷時長,機關為 s | |
minRequestAmount | 熔斷觸發的最小請求數,請求數小于該值時即使異常比率超出門檻值也不會熔斷(1.7.0 引入) | 5 |
statIntervalMs | 統計時長(機關為 ms),如 60*1000 代表分鐘級(1.8.0 引入) | 1000 ms |
slowRatioThreshold | 慢調用比例門檻值,僅慢調用比例模式有效(1.8.0 引入) |
熔斷政策
Sentinel 提供以下幾種熔斷政策:
- 慢調用比例 (SLOW_REQUEST_RATIO):選擇以慢調用比例作為門檻值,需要設定允許的慢調用 RT(即最大的響應時間),請求的響應時間大于該值則統計為慢調用。當機關統計時長(statIntervalMs)内請求數目大于設定的最小請求數目,并且慢調用的比例大于門檻值,則接下來的熔斷時長内請求會自動被熔斷。經過熔斷時長後熔斷器會進入探測恢複狀态(HALF-OPEN 狀态),若接下來的一個請求響應時間小于設定的慢調用 RT 則結束熔斷,若大于設定的慢調用 RT 則會再次被熔斷。慢調用比例 = 統計時長内的慢調用請求數 / 統計時長内的總請求數
- 異常比例 (ERROR_RATIO):當機關統計時長(statIntervalMs)内請求數目大于設定的最小請求數目,并且異常的比例大于門檻值,則接下來的熔斷時長内請求會自動被熔斷。經過熔斷時長後熔斷器會進入探測恢複狀态(HALF-OPEN 狀态),若接下來的一個請求成功完成(沒有錯誤)則結束熔斷,否則會再次被熔斷。異常比率的門檻值範圍是 [0.0, 1.0],代表 0% - 100%。異常比例 = 統計時長内出現的異常請求數 / 統計時長内的總請求數
- 異常數 (ERROR_COUNT):當機關統計時長内的異常數目超過門檻值之後會自動進行熔斷。經過熔斷時長後熔斷器會進入探測恢複狀态(HALF-OPEN 狀态),若接下來的一個請求成功完成(沒有錯誤)則結束熔斷,否則會再次被熔斷。
流控規則與降級規則是在微服務系統中最常用到的兩種方式,其他規則還有熱點參數規則、系統規則、授權規則、黑白名單控制等規則的配置使用可以參考官方的wiki文檔:
https://github.com/alibaba/Sentinel/wiki/。
Feign整合Sentinel
在很多企業中的項目一般都是使用Hystrix來做熔斷的,在上篇文章中也介紹了Sentinel與Hystrix差別,表格對比如下:
項目 | Sentinel | Hystrix |
隔離政策 | 信号量隔離 | 線程池隔離/信号量隔離 |
熔斷降級政策 | 基于響應時間或失敗比率 | 基于失敗比率 |
實時名額實作 | 滑動視窗 | 滑動視窗(基于 RxJava) |
規則配置 | 支援多種資料源 | 支援多種資料源 |
擴充性 | 多個擴充點 | 插件的形式 |
基于注解的支援 | 支援 | 支援 |
限流 | 基于 QPS,支援基于調用關系的限流 | 有限的支援 |
流量整形 | 支援慢啟動、勻速器模式 | 不支援 |
系統負載保護 | 支援 | 不支援 |
控制台 | 開箱即用,可配置規則、檢視秒級監控、機器發現等 | 不完善 |
常見架構的适配 | Servlet、Spring Cloud、Dubbo、gRPC 等 | Servlet、Spring Cloud Netflix |
可以Sentinel在熔斷的實作方式上有更多的靈活配置,同時Sentinel提供了控制台,可以在界面上對接口的限流政策進行調控。Sentinel的生态也是偏向于阿裡系。
整合步驟:
- 添加依賴
<!-- Feign整合Sentinel依賴 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- 添加配置開啟Feign對Sentinel的支援
# 對Feign的支援
feign:
sentinel:
enabled: true # 添加feign對sentinel的支援
- 代碼上保持Hystrix的寫法即可
/**
* @author Seven
* @description
* @部落格:https://codelab7.cn
* @Gitee https://gitee.com/it-codelab
* @Copyright 公衆号:Seven的代碼實驗室
*/
@FeignClient(name = "service-provider", fallback = EchoClientFallback.class)
public interface EchoClient {
@RequestMapping(value = "/echo/{str}", method = RequestMethod.GET)
String echo(@PathVariable("str") String str);
}
/**
* @author Seven
* @description
* @部落格:https://codelab7.cn
* @Gitee https://gitee.com/it-codelab
* @Copyright 公衆号:Seven的代碼實驗室
*/
@Slf4j
@Component
public class EchoClientFallback implements EchoClient {
@Setter
private Throwable e;
@Override
public String echo(String str) {
log.error("進入降級邏輯,異常資訊:{}", e);
return "echo fallback";
}
}
總結
- 本章重點介紹在Sentinel控制台中如何配置流控規則與降級規則,這也是在真實業務場景中最常用的兩種規則。
- 如何使用Feign與Sentinel整合實作熔斷降級。
完整代碼可以在公衆号Seven的代碼實驗室中回複SpringCloudAlibaba擷取。
第0章:總有一篇概述告訴你什麼是微服務
第1章:SpringCloudAlibaba開發環境搭建
第2章:用服務注冊與發現,建構更簡單、更高效的分布式系統
第3章:讓你的微服務更快更穩定:負載均衡的重要性
第4章:讓Feign幫助你輕松實作微服務間的調用
第5章:輕松實作動态配置,Nacos-config帶你走進智能化時代
第6章:解決分布式系統中的挑戰,從容應對複雜性
第7章:Sentinel讓系統輕松掌握流控、熔斷降級、系統負載保護功能