Sentinel 是什么?官網:https://github.com/alibaba/Sentinel/wiki/介紹
隨着微服務的流行,服務和服務之間的穩定性變得越來越重要。Sentinel 以流量為切入點,從流量控制、熔斷降級、系統負載保護等多個維度保護服務的穩定性。
Sentinel 具有以下特征:
- 豐富的應用場景:Sentinel 承接了阿里巴巴近 10 年的雙十一大促流量的核心場景,例如秒殺(即突發流量控制在系統容量可以承受的范圍)、消息削峰填谷、集群流量控制、實時熔斷下游不可用應用等。
- 完備的實時監控:Sentinel 同時提供實時的監控功能。您可以在控制台中看到接入應用的單台機器秒級數據,甚至 500 台以下規模的集群的匯總運行情況。
- 廣泛的開源生態:Sentinel 提供開箱即用的與其它開源框架/庫的整合模塊,例如與 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相應的依賴並進行簡單的配置即可快速地接入 Sentinel。
- 完善的 SPI 擴展點:Sentinel 提供簡單易用、完善的 SPI 擴展接口。您可以通過實現擴展接口來快速地定制邏輯。例如定制規則管理、適配動態數據源等。
Sentinel 的主要特性:
Sentinel 基本概念:
資源:
資源是 Sentinel 的關鍵概念。它可以是 Java 應用程序中的任何內容,例如,由應用程序提供的服務,或由應用程序調用的其它應用提供的服務,甚至可以是一段代碼。在接下來的文檔中,我們都會用資源來描述代碼塊。只要通過 Sentinel API 定義的代碼,就是資源,能夠被 Sentinel 保護起來。大部分情況下,可以使用方法簽名,URL,甚至服務名稱作為資源名來標示資源。
規則:
圍繞資源的實時狀態設定的規則,可以包括流量控制規則、熔斷降級規則以及系統保護規則。所有規則可以動態實時調整。
Sentinel 功能和設計理念:
流量控制:
流量控制在網絡傳輸中是一個常用的概念,它用於調整網絡包的發送數據。然而,從系統穩定性角度考慮,在處理請求的速度上,也有非常多的講究。任意時間到來的請求往往是隨機不可控的,而系統的處理能力是有限的。我們需要根據系統的處理能力對流量進行控制。Sentinel 作為一個調配器,可以根據需要把隨機的請求調整成合適的形狀,如下圖所示:
流量控制設計理念,流量控制有以下幾個角度:
- 資源的調用關系,例如資源的調用鏈路,資源和資源之間的關系;
- 運行指標,例如 QPS、線程池、系統負載等;
- 控制的效果,例如直接限流、冷啟動、排隊等。
Sentinel 的設計理念是讓您自由選擇控制的角度,並進行靈活組合,從而達到想要的效果。
熔斷降級:
除了流量控制以外,降低調用鏈路中的不穩定資源也是 Sentinel 的使命之一。由於調用關系的復雜性,如果調用鏈路中的某個資源出現了不穩定,最終會導致請求發生堆積。Sentinel 和 Hystrix 的原則是一致的: 當檢測到調用鏈路中某個資源出現不穩定的表現,例如請求響應時間長或異常比例升高的時候,則對這個資源的調用進行限制,讓請求快速失敗,避免影響到其它的資源而導致級聯故障。
熔斷降級設計理念:
在限制的手段上,Sentinel 和 Hystrix 采取了完全不一樣的方法。Hystrix 通過 線程池隔離 的方式,來對依賴(在 Sentinel 的概念中對應 資源)進行了隔離。這樣做的好處是資源和資源之間做到了最徹底的隔離。缺點是除了增加了線程切換的成本(過多的線程池導致線程數目過多),還需要預先給各個資源做線程池大小的分配。
Sentinel 對這個問題采取了兩種手段:
- 通過並發線程數進行限制 : 和資源池隔離的方法不同,Sentinel 通過限制資源並發線程的數量,來減少不穩定資源對其它資源的影響。這樣不但沒有線程切換的損耗,也不需要您預先分配線程池的大小。當某個資源出現不穩定的情況下,例如響應時間變長,對資源的直接影響就是會造成線程數的逐步堆積。當線程數在特定資源上堆積到一定的數量之后,對該資源的新請求就會被拒絕。堆積的線程完成任務后才開始繼續接收請求。
- 通過響應時間對資源進行降級 : 除了對並發線程數進行控制以外,Sentinel 還可以通過響應時間來快速降級不穩定的資源。當依賴的資源出現響應時間過長后,所有對該資源的訪問都會被直接拒絕,直到過了指定的時間窗口之后才重新恢復。
系統負載保護:
Sentinel 同時提供系統維度的自適應保護能力。防止雪崩,是系統防護中重要的一環。當系統負載較高的時候,如果還持續讓請求進入,可能會導致系統崩潰,無法響應。在集群環境下,網絡負載均衡會把本應這台機器承載的流量轉發到其它的機器上去。如果這個時候其它的機器也處在一個邊緣狀態的時候,這個增加的流量就會導致這台機器也崩潰,最后導致整個集群不可用。針對這個情況,Sentinel 提供了對應的保護機制,讓系統的入口流量和系統的負載達到一個平衡,保證系統在能力范圍之內處理最多的請求。
Sentinel 的開源生態:
Sentinel 分為兩個部分:
- 核心庫(Java 客戶端)不依賴任何框架/庫,能夠運行於所有 Java 運行時環境,同時對 Dubbo / Spring Cloud 等框架也有較好的支持。
- 控制台(Dashboard)基於 Spring Boot 開發,打包后可以直接運行,不需要額外的 Tomcat 等應用容器。
Sentinel 基本使用:
1.首先,我們需要導入依賴:
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-core</artifactId> <version>1.6.3</version> </dependency>
2.定義資源限流規則:
資源 是 Sentinel 中的核心概念之一。最常用的資源是我們代碼中的 Java 方法。 當然,您也可以更靈活的定義你的資源
//初始化規則 private static void initFlowRules() { List<FlowRule> rules = new ArrayList<>(); //限流規則的集合 FlowRule flowRule = new FlowRule();//限流規則 flowRule.setResource("ruleTest");//資源(可以是方法名稱、接口) //線程數(FLOW_GRADE_THREAD)與QPS (FLOW_GRADE_QPS) flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS); //限流的閾值的類型 flowRule.setCount(18);// QPS數 rules.add(flowRule); FlowRuleManager.loadRules(rules); }
3.啟動測試類,官網提供了以下代碼做演示:
public static void main(String[] args) { initFlowRules(); //初始化一個規則 while(true){ Entry entry=null; try{ entry= SphU.entry("ruleTest"); System.out.println("Hello Word"); }catch (BlockException e){//如果被限流了,那么會拋出這個異常 e.printStackTrace(); }finally { if(entry!=null){ entry.exit();// 釋放 } } } }
Demo 運行之后,我們可以在日志 ~/logs/csp/${appName}-metrics.log.xxx
里看到下面的輸出:
其中 p
代表通過的請求, block
代表被阻止的請求, s
代表成功執行完成的請求個數, e
代表用戶自定義的異常, rt
代表平均響應時長。可以看到,這個程序每秒穩定輸出 "hello world" 18 次,和規則中預先設定的閾值是一樣的。
Sentinel 控制台:
下載 https://github.com/alibaba/Sentinel/releases ,下載 sentinel-dashboard-1.6.3.jar 。(啟動 Sentinel 控制台需要 JDK 版本為 1.8 及以上版本。)
啟動控制台:
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
其中 -Dserver.port=8080
用於指定 Sentinel 控制台端口為 8080
。從 Sentinel 1.6.0 起,Sentinel 控制台引入基本的登錄功能,默認用戶名和密碼都是 sentinel
。
客戶端接入控制台:
將剛剛演示的Demo 接入控制台,首秀按要導入依賴:
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.6.3</version>
</dependency>
啟動時加入 JVM 參數 -Dcsp.sentinel.dashboard.server=consoleIp:port
指定控制台地址和端口。若啟動多個應用,則需要通過 -Dcsp.sentinel.api.port=xxxx
指定客戶端監控 API 的端口(默認是 8719)。其他配置項見:https://github.com/alibaba/Sentinel/wiki/%E5%90%AF%E5%8A%A8%E9%85%8D%E7%BD%AE%E9%A1%B9 配置如下:
-Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-demo
這樣子啟動Demo,客戶端配置好了與控制台的連接參數之后,並不會主動連接上控制台,需要觸發一次客戶端的規則才會開始進行初始化,並向控制台發送心跳和客戶端規則等信息。就能再控制台上看到效果如下:
其他具體相關可以查看github介紹。
Sentinel 整合SpringBoot:
Sentinel 提供了 @SentinelResource
注解用於定義資源,並提供了 AspectJ 的擴展用於自動定義資源、處理 BlockException
等。首先需要導入依賴:
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-core</artifactId> <version>1.6.3</version> </dependency> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-transport-simple-http</artifactId> <version>1.6.3</version> </dependency> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-annotation-aspectj</artifactId> <version>1.6.3</version> </dependency>
在主啟動類中添加規則:
@SpringBootApplication public class SentinelDemoApplication { public static void main(String[] args) { initFlowRules(); SpringApplication.run(SentinelDemoApplication.class, args); } //初始化規則 private static void initFlowRules(){ List<FlowRule> rules=new ArrayList<>(); //限流規則的集合 FlowRule flowRule=new FlowRule(); flowRule.setResource("sayHello");//資源(方法名稱、接口) flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS); //限流的閾值的類型 flowRule.setCount(2); rules.add(flowRule); FlowRuleManager.loadRules(rules); } }
還需要通過配置的方式將 SentinelResourceAspect
注冊為一個 Spring Bean:
@Configuration public class AopConfiguration { @Bean public SentinelResourceAspect sentinelResourceAspect(){ return new SentinelResourceAspect(); } }
此刻我們可以通過注解 @SentinelResource 來定義資源 :
@RestController public class SentinelController { //針對方法級別的限流 @SentinelResource(value = "sayHello", blockHandler = "exceptionHandler", fallback = "fallbackHandler") @GetMapping("/say") public String sayHello(String name) { System.out.println("hello world"); if (1 == 1) throw new RuntimeException("Hello"); return "hello world"; } // 該方法的參數除了 BlockException,包括參數、返回值,需要與原來的資源方法一致 public String exceptionHandler(String name, BlockException ex) { return "blockHandler:" + name + ex.getMessage(); } //用於在拋出異常的時候提供 fallback處理邏輯。 public String fallbackHandler(String name) { return "fallbackHandler:" + name; } }
啟動服務就可以看到效果了。這里需要加入到Sentinel-dashboard中:-Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-demo