Sentinel 教程學習筆記
目錄
-
- 學習進度
- 1. Sentinel 介紹
- 1.1 Sentinel 的組成
- 1.2. Sentinel 的特征
- 1.3. 相關概念
- 2. Sentinel 初體驗
- 2.1 限流規則體驗
- 2.1.1 修改pom.xml添加依賴
- 2.1.2 定義一個Controle來測試CentinelAPI
- 2.1.3 測試限流效果
- 2.2 熔斷降級體驗
- 2.2.1 添加依賴;
- 2.2.2 在controller中定義資源
- 2.2.3 在controller定義熔斷規則
- 2.1 限流規則體驗
- 3. Sentinel 控制台
- 3.1 本地控制台搭建
- 3.2 用戶端接入控制台
- 3.3 Sentinel 定義資源的方式
- 3.3.1 抛出異常的方式
- 3.3.2 傳回布爾值方式定義資源
- 3.3.3 異步調用支援
- 3.3.4 注解方式定義資源
- 4. Sentinel進階
- 4.1 Sentinel 和 SpringCloud整合
- 4.2 Sentinel對Fegin的支援
- 4.3 Sentinel 對 Spring Cloud Gateway 的支援
- 4.4 系統自适應保護
- 4.5 Sentinel授權控制
P19
核心庫(Java 用戶端): 不依賴任何架構 / 庫,能夠運作于所有 Java 運作時環境,同時對 Dubbo / Spring Cloud 等架構也有較好的支援;
控制台(Dashboard): 基于 Spring Boot 開發,打包後可以直接運作,不需要額外的 Tomcat 等應用容器;
豐富的應用場景: Sentinel 承接了阿裡巴巴近 10 年的雙十一大促流量的核心場景,例如秒殺(即突發流量控制在系統容量可以承受的範圍)、消息削峰填谷(對于突然到來的大量請求,您可以配置流控規則,以穩定的速度逐漸處理這些請求,進而避免流量突刺造成系統負載過高)、叢集流量控制、實時熔斷下遊不可用應用等;
完備的實時監控: Sentinel 同時提供實時的監控功能。您可以在控制台中看到接入應用的單台機器秒級資料,甚至 500 台以下規模的叢集的彙總運作情況;
廣泛的開源生态: Sentinel 提供開箱即用的與其它開源架構 / 庫的整合子產品,例如與 Spring Cloud、Dubbo、gRPC 的整合。您隻需要引入相應的依賴并進行簡單的配置即可快速地接入 Sentinel;
完善的 SPI 擴充點: Sentinel 提供簡單易用、完善的 SPI 擴充接口。您可以通過實作擴充接口來快速地定制邏輯。例如定制規則管理、适配動态資料源等;
資源 資源是Sentinel的關鍵概念,它可以是Java應用程式中的任何内容,比如程式提供的服務,或者是一段代碼。隻要通過Sentinel API定義的代碼,就是資源,能夠被Sentinel保護起來。大部分情況下,可以使用方法簽名,URL,甚至服務名稱作為資源名來表示資源。
規則 規則是指圍繞着資源的實時狀态設定的規則,它可以包括流量控制規則、熔斷降級規則以及保護規則。所有規則可以動态實時調整。
流量控制:根據系統的處理能力對流量進行控制,處理不了的請求直接丢棄;
熔斷降級:如果某個資源不穩定,最終會導緻請求發生堆積,在微服務系統中進而導緻級聯錯誤,熔斷機制可以應對這種問題,對資源進行控制,讓請求快速失敗,避免影響其他的資源而産生級聯故障;當資源被降級後,在接下來的降級時間視窗内,對該資源的調用都會自動熔斷(預設行為是抛出DegradeException);
使用SpringBoot工程,通過Sentinel的API來體驗一把資源的限流保護;下面的代碼是通過在代碼中定義限流規則的,在介紹到Sentinel控制台後,我們就可以在控制裡動态的設定限流規則;
<!--添加Sentinel依賴-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.7.2</version>
</dependency>
關鍵點
- SphU.entry 來定義限流入口,并定義資源名稱;
- 使用@PostConstruct注解在構造方法執行後,添加自定義的限流規則;
- BlockException 限流規則被觸發後抛出的異常;
package com.linwei.sentinel.control;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
/**
* @author: linwei
* @date: 2021/7/15 22:41
* @Description:
*/
@RestController
public class TestContorl {
@GetMapping("/hello")
public String hello(){
try (Entry entry = SphU.entry("Hello")){ //限流入口
return "Hello Sentinel!"; //這裡就是被保護的資源
}catch (BlockException ex){
ex.printStackTrace();
return "系統繁忙,稍後重試!"; //限流規則觸發後的操作
}
}
// 定義限流規則
// @PostConstruct 該注解的作用是在目前類的構造原函數執行之後執行的方法
@PostConstruct
public void initFlowRules(){
//1. 建立存放限流規則的集合
List<FlowRule> rules = new ArrayList<>();
//2. 建立限流規則
FlowRule rule1 = new FlowRule();
// 定義資源
rule1.setResource("Hello");
// 定義限流規則類型
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 設定QPS的限流值
rule1.setCount(2);
//3. 将限流規則存放到集合中
rules.add(rule1);
//4. 加載限流規則
FlowRuleManager.loadRules(rules);
}
}
我們在代碼裡設定的限流規則是每秒處理兩個QPS,是以當我們在浏覽器頻繁重新整理請求
/hello
時,就會觸發限流規則;
浏覽器顯示如下:
Hello Sentinel!
系統繁忙,稍後重試!
熔斷降級會在調用鍊路中,某個資源出現不穩定狀态時(例如調用逾時或異常比例升高),對這個資源的調用進行限制,讓請求快速失敗,避免影響到其他的資源導緻級聯錯誤。當資源被降級後,在接下來的降級時間視窗内,對該資源的調用都會自動熔斷(預設行為是抛出DegradeException);
熔斷降級的規則設定有兩種方式:
- 本地代碼設定;
- 在Sentinel控制台動态設定;
以下以本地代碼為例進行示範:
這一步跟上面的2.1.1是一樣的,已經添加過依賴,這一步就可以跳過;
下面是使用了注解的方式定義資源;
@RestController
public class TestController {
// Sentinel 注解方式定義資源; 限流控制
@GetMapping("ann-test")
@SentinelResource(value="sentinel-ann",blockHandler = "exceptionHandler")
public String annotionTest(){
return "hello sentinel annotation";
}
// blockHandler函數
public String exceptionHandler(BlockException ex){
ex.printStackTrace();
return "系統繁忙,請稍後";
}
// Sentinel 注解方式定義資源 熔斷控制
@SentinelResource(value = "sentinel-deg",fallback = "exceptionHandler2")
@RequestMapping("/deg-test")
public String degradeTest(){
return "hello sentinel degrade test!";
}
//降級方法
public String exceptionHandler2(){
return "觸發熔斷降級,系統繁忙,請稍後";
}
}
我們繼續在上面的代碼裡,用代碼的方式進行定義熔斷規則,使用sentinel控制台後,這個步驟就不用要了,隻需要上面定義好資源後,在控制台去定義規則即可;
// 定義熔斷規則
// @PostConstruct 該注解的作用是在目前類的構造原函數執行之後執行的方法
@PostConstruct
public void initFlowRules(){
//1. 建立存放限流規則的集合
List<DegradeRule> rules = new ArrayList<>();
//2. 建立限流規則
DegradeRule rule = new DegradeRule();
// 定義資源
rule.setResource("sentinel-deg");
// 定義限流規則類型:熔斷降級(秒級RT)類型
rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
// 設定門檻值
rule.setCount(0.01);
// 降級的時間視窗,機關為s
rule.setTimeWindow(10);
//3. 将限流規則存放到集合中
rules.add(rule);
//4. 加載限流規則
DegradeRuleManager.loadRules(rules);
}
在浏覽器方式
http://localhost:8080/deg-test
,慢速重新整理可以正常傳回,快速重新整理幾次後,出現
觸發熔斷降級,系統繁忙,請稍後
,并且之後再次重新整理,即使慢速重新整理還是提示繁忙,等待10秒後,又正常顯示了,說明對資源的熔斷降級生效了。
- 下載下傳jar包;
- 方式1:從 release 頁面 下載下傳最新版本的控制台 jar 包(sentinel-dashboard-1.8.2.jar);
- 方式2:也可以從最新版本的源碼自行建構 Sentinel 控制台;
- 啟動jar包
java -Dserver.port=9000 -jar sentinel-dashboard-1.8.2.jar
- 通路Sentinel控制台
浏覽器打開: http://localhost:9000/ 登陸賬号密碼預設均為sentinel;
(參考官網,普通Springboot項目接入Sentinel控制台)
預設情況下Sentinel 會在用戶端首次調用的時候進行初始化,開始向控制台發送心跳包。也可以配置
sentinel.eager=true ,取消Sentinel控制台懶加載。
打開浏覽器即可展示Sentinel的管理控制台。
- 在用戶端pom.xml引入 Transport 子產品來與 Sentinel 控制台進行通信
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.8.2</version>
</dependency>
- 啟動時加入 JVM 參數指定sentinel控制台的Ip和端口,并指定目前用戶端的名稱
-Dcsp.sentinel.dashboard.server=localhost:9000 -Dproject.name=sentinel-demo
完成以上步驟後即可在 Sentinel 控制台上看到對應的應用,機器清單頁面可以看到對應的機器,如果看不到,就通路以下用戶端,因為sentinel預設是懶加載;
- 将代碼裡的限流規則注釋掉,在sentinel控制台添加限流規則
@RestController
public class TestContorl {
@GetMapping("/hello")
public String hello(){
Entry entry = null;
try { //限流入口
entry = SphU.entry("Hello");
return "Hello Sentinel!"; //這裡就是被保護的資源
}catch (BlockException ex){
ex.printStackTrace();
return "系統繁忙,稍後重試!"; //限流規則觸發後的操作
} finally {
if (entry != null) {
entry.exit();
}
ContextUtil.exit();
}
}
// 定義限流規則
// @PostConstruct 該注解的作用是在目前類的構造原函數執行之後執行的方法
/*@PostConstruct
public void initFlowRules(){
//1. 建立存放限流規則的集合
List<FlowRule> rules = new ArrayList<>();
//2. 建立限流規則
FlowRule rule1 = new FlowRule();
// 定義資源
rule1.setResource("Hello");
// 定義限流規則類型
rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
// 設定QPS的限流值
rule1.setCount(2);
//3. 将限流規則存放到集合中
rules.add(rule1);
//4. 加載限流規則
FlowRuleManager.loadRules(rules);
}*/
}

Sentinel 定義資源的方式有以下幾種:
- 抛出異常的方式
- 傳回布爾值方式
- 異步調用支援
- 注解方式
- 主流架構的預設适配
Sentinel中SphU包含了try-catch風格的API,用這種方式,當資源發生了限流之後會抛出BlockException異常。這個時候可以捕獲異常,進行限流之後的邏輯處理,例如:
把需要控制流量的代碼用 Sentinel API SphU.entry("HelloWorld") 和 entry.exit() 包圍起來即可
try (Entry entry = SphU.entry("Hello")){ //限流入口,被保護的資源
return "Hello Sentinel!"; //這裡就是被保護的資源
}catch (BlockException ex){
ex.printStackTrace();
return "系統繁忙,稍後重試!"; //限流規則觸發後的操作
}
Sentinel中SphO的API提供if-else風格的API,用這種方式,當資源發生了限流之後會傳回false,這個時候可以根據傳回值,進行限流之後的邏輯處理;
SphO.entry(xxx)需要與SphO.exit()成對出現,否則會導緻調用鍊記錄異常,抛出ErrorEntryFreeException異常
定義一個測試的controller,然後在Sentinel控制添加對應資源的限流規則,檢視限流時候生效;正常情況下,限流觸發後會執行else裡面的邏輯;
@RequestMapping("boolean-test")
public String booleanTest(){
if(SphO.entry("sentinel-boolean")){ //限流入口,被保護的資源名稱
try {
// 被保護的資源...
return "通路成功!";
}finally {
// SphO.entry(xxx)需要與SphO.exit()成對出現,否則會導緻調用鍊記錄異常,抛出ErrorEntryFreeException異常
SphO.exit(); //限流出口
}
}else{
// 限流規則被觸發後的邏輯處理
return "限流規則觸發,通路失敗!";
}
}
Sentinel支援異步調用鍊路,在異步調用中,需要通過SphU.asyncEntry(XXX)定義資源,并需要在異步回調函數中調用exit方法;
- 在本地引用的引導類中添加注解@EnableAsync, 表示springboot項目開啟異步調用支援;
@EnableAsync
@SpringBootApplication
public class SentinelDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SentinelDemoApplication.class, args);
}
}
- 建立SyncService編寫異步調用方法
@Service
public class MyAsyncService {
// @Async 注解表示該方法為異步調用方法
@Async
public void hello(){
System.out.println("--->異步方法開始");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("--->異步方法結束");
}
}
- 在controller中調用異步方法,實作異步調用限流控制
// Sentinel 對異步調用的支援
@Autowired
private MyAsyncService asyncService;
@GetMapping("async")
public void asyncTest(){
// 1. 進行限流控制
AsyncEntry asyncEntry = null;
try {
asyncEntry = SphU.asyncEntry("sentinel-async"); // 定義限流資源名稱(限流入口)
asyncService.hello(); // 異步方法調用
System.out.println("----continue..."); // 異步方法調用後該語句繼續執行
} catch (BlockException e) {
System.out.println("---> 系統忙,請稍後!"); // 被限流或降級觸發後的邏輯處理
}finally {
if(asyncEntry != null){
asyncEntry.exit(); // 限流出口
}
}
}
Sentinel支援通過注解 @SentinelResource 注解方式定義資源并配置 blockHandler 函數來進行限流之後的處理。
步驟:
-
引入相關依賴;
因為Sentinel中使用AspectJ的擴充用于自定義資源、處理BlockException等,是以需要在項目中引入sentinel-annotation-aspectj依賴;
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>1.8.2</version>
</dependency>
- 建立AspectJ的配置類
@Configuration
public class SentinelAspectConfig {
@Bean
public SentinelResourceAspect sentinelResourceAspect(){
return new SentinelResourceAspect();
}
}
- 建立testController,進行測試驗證;
// Sentinel 注解方式定義資源
@GetMapping("ann-test")
@SentinelResource(value="sentinel-ann",blockHandler = "exceptionHandler")
public String annationTest(){
return "hello sentinel annotation";
}
// blockHandler函數
public String exceptionHandler(BlockException ex){
ex.printStackTrace();
return "系統繁忙,請稍後";
}
SrpingCloudAlibaba 是阿裡巴巴提供,緻力于提供微服務開發的一站式解決方案。Spring Cloud Alibaba 預設為Sentinel 整合了Servlet、RestTemplate、FeignClient和Spring WebFlux。 Sentinel在Spring Cloud生态中,不僅不全了Hystrix在Servlet和RestTemplate這一塊的空白,而且還相容了Hystrix在FeignClent中限流降級的用法,并且支援運作時靈活配置和調整連休降級規則;
具體步驟
- 建立SpringBoot項目,在項目中引入spring-cloud-starter-alibaba-sentinel依賴
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
- 建立Controller用來測試
@RestController
public class TestController {
// Sentinel 注解方式定義資源
@GetMapping("ann-tet")
@SentinelResource(value="sentinel-ann",blockHandler = "exceptionHandler")
public String annotionTest(){
return "hello sentinel annotation";
}
// blockHandler函數
public String exceptionHandler(BlockException ex){
ex.printStackTrace();
return "系統繁忙,請稍後";
}
}
- 在
配置檔案中添加application.properties
控制台配置Sentinel
# 應用名稱
spring.application.name=springcloudsentinel-demo
# 應用服務 WEB 通路端口
server.port=8081
# 設定Sentinel控制台的主機位址和端口
spring.cloud.sentinel.transport.dashboard=localhost:9000
Sentinel
适配了
Feign
元件。如果想要使用,除了引用
spring-cloud-starter-alibaba-sentinel
的依賴,還需要兩個步驟:
- 配置打開
的支援:Sentinel對Feign
feign.sentinel.enable=true
- 加入
依賴使spring-cloud-starter-openfeign
自動化配置類生效Sentinel starter
- 引入Spring Cloud Alibaba Sentinel依賴
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency>
- 在application.properties配置檔案中開啟Sentinel對Feign的支援
#設定Sentinel控制台的主機位址和端口 spring.cloud.sentinel.transport.dashboard=localhost:9000 #打開Sentinel對Feign的支援 feign.sentinel.enabled=true
- 建立FallbackService,作為限流降級回調類,并在FeignAgent進行流控降級回調配置
// 限流或降級的回調類 @Component public class FallbackService implements FeignAgent { //限流和降級的處理 @Override public String hello() { return "系統繁忙,請稍候"; } }
定義feign用戶端接口
// feign 用戶端
@FeignClient(value = "sentinel-feign-provider", fallback = FallbackService.class)
public interface FeignAgent {
@GetMapping("/api/v1/hello")
String hello();
}
服務消費者的測試controller
@RestController
public class TestController{
@Autowired
private FeignAgent feignAgent;
@GetMapping("/hello")
public String hello(){
return feignAgent.hello();
}
}
-
設定限流規則測試
Sentinel與Feign整合時,流控規則的編寫形式為:http請求方式:協定://服務名/請求路徑和參數(請求路徑和參數為@FeignClient中的請求路徑,也就是本服務調用下遊服務的URL)
例如:
如果快速重新整理http://localhost:8090/api/v1/consumer/hello,會出現系統繁忙,請稍候GET:http://sentinel-feign-provider/api/v1/hello
-
請求位址中包含參數的資源名配置
如果是多個@RequestParam,資源名不需要帶上@RequestParam, 如果請求路徑中包含@PathVariable,案例如下:
sentinel控制台資源名定義為:
GET:http://sentinel-feign-provider/api/v1/hello/{hello}
@FeignClient(value = "sentinel-feign-provider", fallback = FallbackService.class) public interface FeignAgent { @GetMapping("/api/v1/hello/{hello}") String hello(@PathVariable(value = "hello") String hello); }
Sentinel整合Spring Cloud gateway
- 在gateway的
中引入依賴;pom.xml
<!-- Spring Cloud Alibaba Sentinel 依賴 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> <version>2.2.3.RELEASE</version> </dependency> <!-- Sentinel支援Spring Cloud Gateway 的依賴 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId> <version>2.2.3.RELEASE</version> </dependency>
- 建立
配置類,配置流控降級回調操作;GatewayConfiguration
@Component public class GatewayConfiguration { @PostConstruct public void doInit(){ //設定限流或降級的回調函數 GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() { @Override public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, java.lang.Throwable throwable) { return ServerResponse.status(200).syncBody("系統繁忙請稍後"); } }); } }
-
中配置application.yaml
控制台通路位址;sentinel
spring: cloud: sentinel: transport: port: 8718 dashboard: 127.0.0.1:8080
- 運作測試;
sentinel
在适配
spring cloud gateway
時提供了兩種配置規則:
:即在spring配置檔案配置的路由條數,資源名為對應的
route次元
;
routeId
- 自定義API次元:使用者可以利用
提供的API來自定義一些自定義分組;
Sentinel
在sentinel控制台中,添加網關限流規則的界面跟普通限流規則的界面不太相同,如下圖:
API類型選擇Route ID , 就是輸入gateway中路徑的routeid; 如果選擇的是API分組,就需要先在Sentinel控制台網關目錄下的菜單“API管理” 裡定義API分組,然後在添加留白規則的這個界面上選擇API分組;
Sentinel系統自适應限流是從應用的整體次元進行入口流量控制,結合應用的Load,CPU使用率,總體平均RT,入口QPS和并發線程數等幾個次元的監控名額,通過自适應的流控政策,來讓系統入口流量和系統的負載達到一個平衡,讓系統盡可能保持最大吞吐量的同時保證系統整體的穩定性;
- 本地代碼方式;
- Sentinel控制台動态配置;
@RestController
public class SysController {
// 這裡定義的資源就沒有定義資源的名稱和處理函數了,因為系統自适應的次元是整個應用,sentinel也會有預設的限流和降級的處理函數;
// EntryType.IN 表示這是一個入口資源,自适應保護也隻對這樣的入口資源生效;
@SentinelResource(entryType = EntryType.IN)
@RequestMapping("/sys")
public String sysHello(){
return "hello sentinel!";
}
// 代碼方式定義規則
@PostConstruct
private void initSystemRule(){
//1. 建立存放限流規則的集合
List<SystemRule> rules = new ArrayList<>();
//2. 建立自适應規則
SystemRule rule = new SystemRule();
// 設定入口QPS
rule.setQps(2);
//3. 将限流規則存放到集合中
rules.add(rule);
//4. 加載限流規則
SystemRuleManager.loadRules(rules);
}
}