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 / blockHandlerClassblockHandler 对应处理 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处理");
//    }

}

 

posted @ 2021-11-27 16:40  残星  阅读(192)  评论(0编辑  收藏  举报