Sentinel基本使用
第一步:POM文件
<?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.11.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>sentinel</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <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> </dependencies> </project>
第二部:配置bean——SentinelResourceAspect
package com.sentinel; import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; /** * @author vans on 2022/2/23 15:16 */ @SpringBootApplication @Slf4j public class VnSentinelApplication { public static void main(String[] args) { SpringApplication.run(VnSentinelApplication.class,args); } // 注解支持的配置Bean @Bean public SentinelResourceAspect sentinelResourceAspect() { return new SentinelResourceAspect(); } }
第三步:
package com.sentinel.controller; import com.alibaba.csp.sentinel.Entry; import com.alibaba.csp.sentinel.EntryType; 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.degrade.DegradeRule; import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager; import com.alibaba.csp.sentinel.slots.block.flow.FlowRule; import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager; import com.sentinel.common.Contants; import com.sentinel.entity.User; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; 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; /** * @author vans on 2022/2/23 15:18 */ @RestController @RequestMapping("/vn/sentinel") @Slf4j public class VnSentinelController { @GetMapping public User getUser() { Entry entry = null; try { // 1.sentinel针对资源进行限制的 entry = SphU.entry(Contants.RESOURCE_NAME); // 被保护的业务逻辑 String str = "hello world"; log.info("=====" + str + "====="); return new User("vn", 18); } catch (BlockException e1) { // 资源访问阻止,被限流或被降级 //进行相应的处理操作 log.info("block!"); return new User("vn被流控", 18); } catch (Exception ex) { // 若需要配置降级规则,需要通过这种方式记录业务异常 Tracer.traceEntry(ex, entry); } finally { if (entry != null) { entry.exit(); } } return null; } @PostConstruct // 初始化 public void initDegradeRule(){ /*降级规则 异常*/ List<DegradeRule> degradeRules = new ArrayList<>(); DegradeRule degradeRule = new DegradeRule(); degradeRule.setResource(Contants.DEGRADE_RESOURCE_NAME); // 设置规则侧率: 异常数 degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT); // 触发熔断异常数 : 2 degradeRule.setCount(2); // 触发熔断最小请求数:2 degradeRule.setMinRequestAmount(2); // 统计时长: 单位:ms 1分钟 degradeRule.setStatIntervalMs(60*1000); // 时间太短不好测 // 一分钟内: 执行了2次 出现了2次异常 就会触发熔断 // 熔断持续时长 : 单位 秒 // 一旦触发了熔断, 再次请求对应的接口就会直接调用 降级方法。 // 10秒过了后——半开状态: 恢复接口请求调用, 如果第一次请求就异常, 再次熔断,不会根据设置的条件进行判定 degradeRule.setTimeWindow(10); degradeRules.add(degradeRule); DegradeRuleManager.loadRules(degradeRules); /* 慢调用比率--DEGRADE_GRADE_RT degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_RT); degradeRule.setCount(100); degradeRule.setTimeWindow(10); //请求总数小于minRequestAmount时不做熔断处理 degradeRule.setMinRequestAmount(2); // 在这个时间段内2次请求 degradeRule.setStatIntervalMs(60*1000*60); // 时间太短不好测 // 慢请求率:慢请求数/总请求数> SlowRatioThreshold , // 这里要设置小于1 因为慢请求数/总请求数 永远不会大于1 degradeRule.setSlowRatioThreshold(0.9);*/ } /** * 定义流控规则 * <p> * spring 的初始化方法 */ @PostConstruct private static void initFlowRules() { // 流控规则 List<FlowRule> rules = new ArrayList<>(); // 流控 FlowRule rule = new FlowRule(); rule.setResource(Contants.RESOURCE_NAME); // 设置流控规则 QPS (1秒钟访问量) rule.setGrade(RuleConstant.FLOW_GRADE_QPS); // 设置受保护的资源阈值(每秒最多允许通过1次请求) rule.setCount(1); rules.add(rule); // 流控 FlowRule ruleo = new FlowRule(); ruleo.setResource(Contants.USER_RESOURCE_NAME); // 设置流控规则 QPS (1秒钟访问量) ruleo.setGrade(RuleConstant.FLOW_GRADE_QPS); // 设置受保护的资源阈值(每秒最多允许通过1次请求) ruleo.setCount(1); rules.add(ruleo); FlowRuleManager.loadRules(rules); } /** * @SentinelResource 改善接口中资源定义和被流控降级后的处理方法 * * 怎么使用: 1.添加依赖<artifactId>sentinel-annotation-aspectj</artifactId> * 2.配置bean——SentinelResourceAspect * * value 定义资源 * blockHandler 设置 流控降级后的处理方法(默认该方法必须声明在同一个类) * 如果不想在同一个类中 blockHandlerClass 但是方法必须是static * * fallback 当接口出现了异常,就可以交给fallback指定的方法进行处理 * 如果不想在同一个类中 fallbackClass 但是方法必须是static * * 如果blockHandler和fallback同时指定了,则blockHandler优先级更高 * * exceptionsToIgnore 排除哪些异常不处理 */ @RequestMapping("/user") @SentinelResource(value = Contants.USER_RESOURCE_NAME, fallback = "fallbackHandleForGetUser", blockHandler = "blockHandlerForGetUser") public User getUsers(String id) { int a=1/0; return new User("vn_sentinelResource", 18); } /** * 控流异常方法 */ public User fallbackHandleForGetUser(String id, Throwable e) { e.printStackTrace(); return new User("fallbackHandleForGetUser异常处理", 11); } /** * 控流方法 * * 注意: * 1. 一定要public * 2. 返回值一定要和源方法保证一致, 包含源方法的参数。 * 3. 可以在参数最后添加BlockException 可以区分是什么规则的处理方法 */ public User blockHandlerForGetUser(String id, BlockException ex) { ex.printStackTrace(); return new User("blockHandlerForGetUser流控!!", 16); } @RequestMapping("/degrade") @SentinelResource(value = Contants.DEGRADE_RESOURCE_NAME,entryType = EntryType.IN, blockHandler = "blockHandlerForFb") public User degrade(String id) throws InterruptedException { // 异常数\比例 throw new RuntimeException("异常"); /* 慢调用比例 TimeUnit.SECONDS.sleep(1); return new User("正常");*/ } public User blockHandlerForFb(String id, BlockException ex) { return new User("熔断降级"); } }