Alibaba微服務元件 - Sentinel(三)
阿新 • • 發佈:2022-04-13
3. Sentinel快速開始(API實現)
文件地址:https://github.com/alibaba/Sentinel/wiki/如何使用
在官方文件中,定義的Sentinel進行資源保護的幾個步驟:
1. 定義資源
2. 定義規則
3. 檢驗規則是否生效
sentinel可以自己作為一個元件在分散式專案中使用,我們先來實現sentinel-core使用
3.1 引入依賴
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.2.RELEASE</version> <relativePath/> </parent> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>sentinel-demo</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--sentinel核心庫--> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-core</artifactId> <version>1.8.0</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.18</version> </dependency> <!--如果要使用@SentinelResource--> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-annotation-aspectj</artifactId> <version>1.8.0</version> </dependency> <!--整合sentinel控制檯--> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-transport-simple-http</artifactId> <version>1.8.0</version> </dependency> </dependencies> </project>
3.2 配置bean SentinelResourceAspect
(單獨使用的話必須注入bean,這個切面沒有定義@Component)
package com.xiexie.sentinel; import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; /** * @Description * @Date 2022-04-13 9:11 * @Author xie */ @SpringBootApplication public class HelloApplication { public static void main(String[] args) { SpringApplication.run(HelloApplication.class, args); } @Bean public SentinelResourceAspect sentinelResourceAspect() { return new SentinelResourceAspect(); } }
3.3 編寫測試邏輯
缺點:
- 業務侵入性很強,需要在controller中寫入非業務程式碼.
- 配置不靈活 若需要新增新的受保護資源 需要手動新增 init方法來新增流控規則
演示流控規則
package com.xiexie.sentinel.controller; import com.alibaba.csp.sentinel.Entry; import com.alibaba.csp.sentinel.SphU; import com.alibaba.csp.sentinel.Tracer; import com.alibaba.csp.sentinel.annotation.SentinelResource; 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 com.xiexie.sentinel.Entry.User; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.PostConstruct; import java.util.ArrayList; import java.util.List; import java.util.Objects; /** * @Description 演示流控規則(一般放在服務消費端) * @Date 2022-04-13 9:10 * @Author xie */ @RestController @Slf4j public class FlowRuleController { // resource name 需要跟介面地址相同(通過介面地址定義資源名稱) // 資源名可使用任意有業務語義的字串,比如方法名、介面名或其它可唯一標識的字串。 private static final String RESOURCE_NAME = "hello"; private static final String USER_RESOURCE_NAME = "user"; private static final String DEGRADE_RESOURCE_NAME = "degrade"; /** * sentinel進行流控(硬編碼形式) * @return java.lang.String */ @RequestMapping("/hello") public String hello() { Entry entry = null; // sentinel針對資源進行限制 try { entry = SphU.entry(RESOURCE_NAME); // 被保護的業務邏輯 String str = "hello sentinel"; log.info("=====" + str + "====="); return str; } catch (BlockException e) { e.printStackTrace(); // 資源訪問阻止,被限流或者被降級 // 進行相應的業務處理 log.info("被限流了。。。"); return "被限流了。。。"; } catch (Exception e) { // 若需要配置降級規則,需要用這種方式記錄業務異常 Tracer.traceEntry(e, entry); } finally { if (Objects.nonNull(entry)) { entry.exit(); } } return null; } /** * 定義流控規則 * * @date 2022/4/13 9:34 */ @PostConstruct // 相當於bean的 init-method private void initFlowRules() { // 流控規則集合 // 還有其他規則道理相同,比如:熔斷降級規則 (DegradeRule)、系統保護規則 (SystemRule)、訪問控制規則 (AuthorityRule)、熱點規則 (ParamFlowRule) List<FlowRule> flowRuleList = new ArrayList(); // 定義流控規則 FlowRule flowRule1 = new FlowRule(); // 設定受保護的資源 flowRule1.setResource(RESOURCE_NAME); // 設定流控規則 限流閾值型別,QPS 模式(1)或併發執行緒數模式(0) flowRule1.setGrade(RuleConstant.FLOW_GRADE_QPS); // 設定保護限流閾值(整合起來就是1s 只能訪問一次) flowRule1.setCount(1); flowRuleList.add(flowRule1); // 通過@SentinelResource來定義資源的流控和降級規則 FlowRule flowRule2 = new FlowRule(); // 設定受保護的資源 flowRule2.setResource(USER_RESOURCE_NAME); // 設定流控規則 限流閾值型別,QPS 模式(1)或併發執行緒數模式(0) flowRule2.setGrade(RuleConstant.FLOW_GRADE_QPS); // 設定保護限流閾值(整合起來就是1s 只能訪問一次) flowRule2.setCount(1); flowRuleList.add(flowRule2); // 載入配置好的規則 FlowRuleManager.loadRules(flowRuleList); } /********************************* 使用@SentinelResource改善硬編碼格式 ****************************/ /** * @SentinelResource 改善介面中資源定義和被流控降級後的處理方法 * 使用: * 1. 新增依賴:<artifactId>sentinel-annotation-aspectj</artifactId> * 2. 配置bean SentinelResourceAspect(單獨使用的話必須注入bean,這個切面沒有定義@Component) * value:定義資源 * blockHandler:設定流控降級後的處理方法(預設該方法必須跟流控介面宣告在同一個類中) * 如果不想在同一個類中可以用blockHandlerClass來指定,但是方法必須是public static修飾 * fallback:當接口出現了異常,就可以交給fallback執行的方法進行處理 * 如果不想在同一個類中可以用fallbackClass來指定,但是方法必須是public static修飾 * 優先順序:blockHandler > fallback * exceptionsToIgnore:要排除的異常 * * @param id * @return com.xiexie.sentinel.Entry.User */ @RequestMapping("/user") @SentinelResource(value = USER_RESOURCE_NAME , blockHandler = "blockHandlerForGetUser" , blockHandlerClass = {User.class} , fallback = "fallbackForGetUser" , exceptionsToIgnore = {ArithmeticException.class} ) public User getUser(String id) { //int a = 1/0; return new User("xiexie"); } /** * 注意: * 1. 一定要是public修飾 * 2. 返回值一定要跟源方法一致,包含源方法引數(順序也要一致) * 3. 可以在引數中加BlockException異常處理,可以區分是什麼型別的規則,對症下藥。 * @param id * @param e * @return com.xiexie.sentinel.Entry.User */ public User blockHandlerForGetUser(String id, BlockException e) { e.printStackTrace(); return new User("被流控"); } public User fallbackForGetUser(String id, Throwable throwable) { throwable.printStackTrace(); return new User("異常處理"); } }
演示熔斷降級規則
package com.xiexie.sentinel.controller;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.xiexie.sentinel.Entry.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
/**
* @Description 演示熔斷降級規則(一般放在服務提供端)
* @Date 2022-04-13 11:21
* @Author xie
*/
@RestController
public class DegradeRuleController {
private static final String DEGRADE_RESOURCE_NAME = "degrade";
@RequestMapping("/degrade")
@SentinelResource(value = DEGRADE_RESOURCE_NAME, entryType = EntryType.IN, blockHandler = "blockHandlerForDegrade")
public User degrade(String id) {
// 異常數 比例
throw new RuntimeException("異常了");
}
public User blockHandlerForDegrade(String id, BlockException e) {
e.printStackTrace();
return new User("觸發熔斷, 開始降級操作");
}
/**
* 初始化熔斷降級規則
* @date 2022/4/13 11:22
*/
@PostConstruct
public void initDegradeRule() {
// 降級規則異常
List<DegradeRule> degradeRuleList = new ArrayList();
DegradeRule degradeRule = new DegradeRule();
degradeRule.setResource(DEGRADE_RESOURCE_NAME);
// 熔斷降級策略 支援慢呼叫比例/異常比例/異常數策略(預設值慢呼叫比例)
degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
// 觸發熔斷異常數 2個
degradeRule.setCount(2);
// 觸發熔斷最小請求數 2次
degradeRule.setMinRequestAmount(2);
// 統計時長 (時間太短不好測試)1分鐘 單位ms 預設1s
degradeRule.setStatIntervalMs(60 * 1000);
// --- 上述條件就是:一分鐘內 請求了兩次+ 出現了兩次異常 就會觸發熔斷
// 熔斷時長 單位s
// 具體說明:一旦觸發了熔斷,再次請求介面就會直接呼叫降級方法,而不是介面本身
// 10s過後進入半開狀態,恢復介面本身呼叫,如果第一次請求就出現了異常,再次熔斷,不會根據設定的條件進行判定
// 然後繼續重複上述操作。
degradeRule.setTimeWindow(10);
degradeRuleList.add(degradeRule);
DegradeRuleManager.loadRules(degradeRuleList);
}
}
3.4 @SentinelResource註解實現
@SentinelResource 註解用來標識資源是否被限流、降級。
blockHandler: 定義當資源內部發生了BlockException應該進入的方法(捕獲的是Sentinel定義的異常)
fallback: 定義的是資源內部發生了Throwable應該進入的方法
exceptionsToIgnore:配置fallback可以忽略的異常
原始碼入口:com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect
// 程式碼如上
3.5 規則的種類
- 流量控制規則
- 熔斷降級規則
- 系統保護規則
- 訪問控制規則
- 熱點規則
剩下規則演示請檢視官方文件,基本是一樣的操作
https://github.com/alibaba/Sentinel/wiki/如何使用
3.6 如果需要控制檯展示
控制檯官方文件:https://github.com/alibaba/Sentinel/wiki/控制檯
客戶端需要引入 Transport 模組來與 Sentinel 控制檯進行通訊。
<!--整合sentinel控制檯-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.8.0</version>
</dependency>
並且設定JVM引數
‐Dcsp.sentinel.dashboard.server=youConsoleIp:port