Spring Cloud Alibaba Sentinel @SentinelResource
https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81
https://blog.didispace.com/spring-cloud-alibaba-sentinel-2-5/
@SentinelResource
用于定义资源,并提供可选的异常处理和 fallback 配置项。 @SentinelResource
注解包含以下属性:
value
:资源名称,必需项(不能为空)entryType
:entry 类型,可选项(默认为EntryType.OUT
)blockHandler
/blockHandlerClass
:blockHandler
对应处理BlockException
的函数名称,可选项。blockHandler 函数访问范围需要是public
,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为BlockException
。blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定blockHandlerClass
为对应的类的Class
对象,注意对应的函数必需为 static 函数,否则无法解析。fallback
/fallbackClass
:fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了exceptionsToIgnore
里面排除掉的异常类型)进行处理。fallback 函数签名和位置要求:- 返回值类型必须与原函数返回值类型一致;
- 方法参数列表需要和原函数一致,或者可以额外多一个
Throwable
类型的参数用于接收对应的异常。 - fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定
fallbackClass
为对应的类的Class
对象,注意对应的函数必需为 static 函数,否则无法解析。
defaultFallback
(since 1.6.0):默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。默认 fallback 函数可以针对所有类型的异常(除了exceptionsToIgnore
里面排除掉的异常类型)进行处理。若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。defaultFallback 函数签名要求:- 返回值类型必须与原函数返回值类型一致;
- 方法参数列表需要为空,或者可以额外多一个
Throwable
类型的参数用于接收对应的异常。 - defaultFallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定
fallbackClass
为对应的类的Class
对象,注意对应的函数必需为 static 函数,否则无法解析。
exceptionsToIgnore
(since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。
package com.wsm.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.alibaba.csp.sentinel.slots.system.SystemRule; import com.alibaba.csp.sentinel.slots.system.SystemRuleManager; import com.wsm.sentinel.handler.HelloBlockHandler; import com.wsm.sentinel.pojo.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; import java.util.concurrent.TimeUnit; @RestController @Slf4j public class HelloController { private static final String RESOURCE_NAME="hello"; private static final String USER_RESOURCE_NAME = "user"; private static final String DEGRADE_RESOURCE_NAME = "degrade"; //进行sentinel限流 @RequestMapping(value = "/hello") public String hello() { Entry entry = null; try { //sentinel 针对资源进行限制 entry = SphU.entry(RESOURCE_NAME); //被保护的业务逻辑 String str = "hello world"; log.info("======="+str+"========"); return str; }catch (BlockException el){ //资源访问阻止,被限流或被降级 //进行相应的处理操作 log.info("block!"); return "被流控了!"; }catch (Exception ex){ //若需要配置降级,需要通过这种方式记录业务异常 Tracer.traceEntry(ex,entry); }finally { if(entry != null){ entry.exit(); } } return null; } /** * 定义规则 * * spring 的初始化方法 */ @PostConstruct // init-method Spring注解 Bean创建的时候会调用这个方法进行初始化 private static void initFlowRules(){ // //流控规则 // List<FlowRule> rules = new ArrayList<>(); // //流控 // FlowRule rule = new FlowRule(); // //设置受保护的资源 // rule.setResource(RESOURCE_NAME); // //设置流控规则 QPS // rule.setGrade(RuleConstant.FLOW_GRADE_QPS); // //设置受保护的资源阈值 QPS每秒访问数 // rule.setCount(1); // rules.add(rule); // // //流控 // FlowRule rule2 = new FlowRule(); // //设置受保护的资源 // rule2.setResource(USER_RESOURCE_NAME); // //设置流控规则 QPS // rule2.setGrade(RuleConstant.FLOW_GRADE_QPS); // //设置受保护的资源阈值 QPS每秒访问数 // rule2.setCount(1); // rules.add(rule2); // FlowRuleManager.loadRules(rules); } @PostConstruct public void initDegradeRules(){ // 一秒内(请求数大于等于 5)响应时间超过某个值:RuleConstant.DEGRADE_GRADE_RT; // 一秒内(请求数大于等于 5)的错误比率:RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO; // 一分钟内的错误数量:RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT; List<DegradeRule> rules = new ArrayList<>(); DegradeRule rule = new DegradeRule(); rule.setResource(DEGRADE_RESOURCE_NAME); //异常数模式下为对应的阈值 rule.setCount(2); //熔断策略,异常数策略 rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT); // 熔断时长,单位为 s rule.setTimeWindow(10); // rule.setMinRequestAmount(2); // rule.setStatIntervalMs(60*1000*60);//时间太短不好测 rules.add(rule); // DegradeRule rule1 = new DegradeRule(); // rule1.setResource(DEGRADE_RESOURCE_NAME); // //异常比例模式下为对应的阈值 // rule1.setCount(0.1); // //熔断策略,异常比例策略 // rule1.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO); // // 熔断时长,单位为 s // rule1.setTimeWindow(10); //// rule1.setMinRequestAmount(2); //// rule1.setStatIntervalMs(60*1000*60);//时间太短不好测 // rules.add(rule1); // DegradeRule rule2 = new DegradeRule(); // rule2.setResource(DEGRADE_RESOURCE_NAME); // //慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用); // // set threshold RT, 10 ms // rule2.setCount(10); // //熔断策略,支持慢调用比例 -- DEGRADE_GRADE_RT // rule2.setGrade(RuleConstant.DEGRADE_GRADE_RT); // // 熔断时长,单位为 s // rule2.setTimeWindow(10); //// 请求总数小于minRequestAmount(2); // rule2.setMinRequestAmount(2); //// 在这个时间段内2次请求 // rule2.setStatIntervalMs(60*1000*60);//时间太短不好测 //// 慢请求率: 慢请求数/总请求数> SlowRatioThreshold , 这里要设置小于1 因为慢请求数/总请求数就远不会大于1 // rule2.setSlowRatioThreshold(0.9); // rules.add(rule2); DegradeRuleManager.loadRules(rules); } // 限流规则 private void initFlowQpsRule() { List<FlowRule> rules = new ArrayList<>(); FlowRule rule = new FlowRule(RESOURCE_NAME); // set limit qps to 20 rule.setCount(20); rule.setGrade(RuleConstant.FLOW_GRADE_QPS); rule.setLimitApp("default"); rules.add(rule); FlowRuleManager.loadRules(rules); } private void initDegradeRule() { List<DegradeRule> rules = new ArrayList<>(); DegradeRule rule = new DegradeRule(); rule.setResource(DEGRADE_RESOURCE_NAME); // set threshold RT, 10 ms rule.setCount(10); rule.setGrade(RuleConstant.DEGRADE_GRADE_RT); rule.setTimeWindow(10); rules.add(rule); DegradeRuleManager.loadRules(rules); } private void initSystemRule() { List<SystemRule> rules = new ArrayList<>(); SystemRule rule = new SystemRule(); rule.setHighestSystemLoad(10); rules.add(rule); SystemRuleManager.loadRules(rules); } @GetMapping("/rule_setting") //代码配置sentinel限流规则 public String initFlowRule(){ //规则集合 List<FlowRule> rules = new ArrayList<>(); //创建新的规则对象,"/list"就是资源名 FlowRule rule = new FlowRule("/list"); //直接策略 rule.setStrategy(RuleConstant.STRATEGY_DIRECT); //采用QPS限速模式 rule.setGrade(RuleConstant.FLOW_GRADE_QPS); //限制QPS为100 rule.setCount(100); //流控效果设置为“预热” rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP); //预热时间20秒 rule.setWarmUpPeriodSec(20); //来源设置为默认所有default rule.setLimitApp("default"); rules.add(rule); //设置,FlowRuleManager是Sentinel规则管理器 FlowRuleManager.loadRules(rules); return "SUCCESS"; } /** * @SentinelResource 改善接口中资源定义和被流控降级后的处理方法 * 使用方法: * 1.添加依赖 <artifactId>sentinel-annotation-aspectj</artifactId> * 2.配置 Bean - SentinelResourceAspect * value 定义资源 * blockHandler 设置流控降级后的处理方法(默认该方法必须声明在同一个类) * blockHandlerClass blockHandler不在同一个类时设置,在同一个类中时不用设置 * fallback 当接口出现了异常,就可以交给fallback指定的方法进行处理 * @param id * @return */ @RequestMapping("/user") @SentinelResource(value = USER_RESOURCE_NAME, // fallbackClass = HelloBlockHandler.class, // fallback = "fallbackForGetUser", // blockHandlerClass = HelloBlockHandler.class, blockHandler = "blockHandlerForGetUser" ) public User getUser(String id) { log.info("====getUser======"); return new User("wsmen"); } /** * 注意: * 1. 一定要是public方法 * 2. 返回方法一定要和源方法保持一致, 包含源方法的参数 * 3. 可以在参数最后添加BlockException, 可以区分是什么规则的处理方法 * @param id * @param ex * @return */ public User blockHandlerForGetUser(String id,BlockException ex){ ex.printStackTrace(); return new User("流控!!"); } // // 这里单独演示 blockHandlerClass 的配置. // // 对应的 `handleException` 函数需要位于 `ExceptionUtil` 类中,并且必须为 public static 函数. // @SentinelResource(value = "test", blockHandler = "handleException", blockHandlerClass = {ExceptionUtil.class}) // public void test() { // System.out.println("Test"); // } @RequestMapping("/degrade") @SentinelResource(value = DEGRADE_RESOURCE_NAME,entryType = EntryType.IN, // fallback = "fallbackForFb", 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("异常处理"); } // public User fallbackForFb(String id,BlockException ex){ // return new User("异常fallback处理"); // } }