sentinel入门使用

1.简介

微服务体系架构下,服务容错是一个大事,常见的容错方案有

  • 超时

  • 流控(限流)

  • 熔断降级

在业界也有很多可选择的容错产品,比如说服务之间调用ribbon+resttemplate支持超时设置,feign支持超时,甚至我们在设计实现api的时候,也会考虑相关的api超时机制。

比如说支持流控、熔断降级的产品hystrix、resilience4j,以及阿里开源的sentinel。

当然今天我们的主角是sentinel,因为它的优秀,我准备写一个短系列文章分享介绍使用它!整理了一下,内容大致包括

  • 入门使用

  • 控制台dashboard

  • spring cloud alibba 整合sentinel使用

  • 扩展sentinel之错误页面

  • 扩展sentinel之区分来源

  • 扩展sentinel之支持restful url

  • 扩展sentinel之规则持久化

本篇文章是第一篇,我们从入门开始!

2.sentinel介绍

关于sentinel介绍,我想推荐你去看官网,非常详细!这也是我想推荐给小伙伴们学习新东西的一个方式

  • 一定要看官网,一定要掌握学习的方法,总结形成自己的知识体系!

  • 反之,如果我们只是满足于借助搜索引擎翻几篇文章,比如说吧就看我的博客,那是远远不够的!

  • 借助搜索引擎,看看博客,只能是快速入门!所以还是那句话:一定要看官网

那么官网的地址在哪呢?github,我贴一下它的地址:

https://github.com/alibaba/Sentinel/wiki/%E4%B8%BB%E9%A1%B5

顺便截个图:

总结一下,官方的介绍

  • sentinel是一个服务稳定性的防护组件,流控、熔断降级规则丰富,应用场景丰富

  • 还提供的dashboard控制面板,相关规则管理,比如说规则动态配置刷新;支持监控

  • 更关键的是sentinel不依赖任何第三方库,或者开源组件,这就很感人了!不管是普通sevlet web应用,老一代spring web应用,还是springboot应用,还是整合到spring cloud应用,统统都满足!

3.入门案例

3.1.搭建环境

我这里以springboot应用为例,毕竟springboot今天是主流应用基础框架。首先我们需要引入sentinel依赖

<!--公共变量定义-->
<properties>
  <java.version>1.8</java.version>
  <spring-boot.version>2.3.2.RELEASE</spring-boot.version>
</properties>

<!--sentinel依赖-->
<dependency>
  <groupId>com.alibaba.csp</groupId>
  <artifactId>sentinel-core</artifactId>
  <version>1.8.2</version>
</dependency>

这里关于版本的选择,我贴一个官方的地址:https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E

因为我这里选择的springboot版本是:2.3.2.RELEASE,所以sentinel版本参照官网选择的版本是:1.8.2

3.2.加载规则

对于sentinel防护组件,使用的关键是两个点

  • 声明资源

  • 定义相关规则,保护资源

3.2.1.声明资源

 

/**
 * <p>
 * sentinel 资源
 * </p>
 *
 * @author [email protected]
 * @since 2021/8/5
 */
public interface MySentinelResource {
    /**
     * 流控资源
     */
    public static final String FLOW_RESOURCE = "flowResource";
}

3.2.2.加载资源

/**
 * <p>
 * 加载sentinel规则
 * 1.流控规则
 * 2.降级规则
 * 3.系统规则
 * 4.热点规则
 * 5.授权规则
 * </p>
 *
 * @author [email protected]
 * @since 2021/8/5
 */
@Component
@Slf4j
public class LoadSentinelRules {

    public LoadSentinelRules(){
        // 初始化加载流控规则
        initFlowRules();
        log.info("加载了流控规则.");

    }


    /**
     * 初始化流控规则
     */
    public void initFlowRules(){
        // 流控规则集合
        List<FlowRule> flowRules = Lists.newArrayList();

        FlowRule rule = new FlowRule();
        rule.setResource(MySentinelResource.FLOW_RESOURCE);// 资源
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS); // 流控阈值类型:qps
        rule.setCount(1);// 流控阈值:1

        flowRules.add(rule);

        FlowRuleManager.loadRules(flowRules);
    }

}

3.3.流控规则

编写一个conttroller,将相关的端点作为资源,通过sentinel进行保护

/**
 * <p>
 * sentinel demo controller
 * </p>
 *
 * @author [email protected]
 * @since 2021/8/5
 */
@RestController
@RequestMapping("sentinel")
@Slf4j
public class SentinelController {

    @RequestMapping("flow")
    public String flow(String userId){
        Entry entry = null;
        String result = "ok!";
        try{
            // 1.开始进入资源,流控保护开始
            SphU.entry(MySentinelResource.FLOW_RESOURCE);

            // 2.被保护的资源
            log.info("SentinelController--flow,param:{}", userId);

        }catch (BlockException e){
            log.error("发生流控异常! msg:{}", e);
            result = "error!限流了!";
        }finally {
            // 3.释放资源,需要与SphU.entry配对
            if(entry != null){
                entry.exit();
            }
        }

       return result;
    }
}

关键代码说明

  • 第一步,通过SphU.entry方法声明进入资源

  • 第二步,编写需要被保护资源

  • 第三步,通过 entry.exit释放资源

3.4.流控效果

把应用启动起来,我们上面配置一个流控规则,表示每秒中允许通过的qps是1,超过1即需要流控(限流)

 

请求api:http://127.0.0.1:8080/sentinel/flow?userId=1,1秒内多次刷新

3.5.熔断降级规则

通过上面的案例,我们看到了sentinel流控的效果。不过实现的代码,看起来比较糟糕!你还记得这段代码吗?

 @RequestMapping("flow")
    public String flow(String userId){
        Entry entry = null;
        String result = "ok!";
        try{
            // 1.开始进入资源,流控保护开始
            SphU.entry(MySentinelResource.FLOW_RESOURCE);

            // 2.被保护的资源
            log.info("SentinelController--flow,param:{}", userId);

        }catch (BlockException e){
            log.error("发生流控异常! msg:{}", e);
            result = "error!限流了!";
        }finally {
            // 3.释放资源,需要与SphU.entry配对
            if(entry != null){
                entry.exit();
            }
        }

       return result;
    }

需要通过

  • try{...}catch(BlockException e){...}finally{...}代码块

  • SphU.entry声明资源开始

  • 通过entry.exit声明保护资源结束

实际项目中,如果每个需要作为资源被保护起来的业务方法,都这么去写,相信小伙伴们一定很抓狂!

那么有没有什么更好的实现方法呢?答案是有,sentinel给我们提供了一个@SentinelResource注解,只需要在业务方法上加上该注解,那么sentinel就会自动把该业务方法作为资源保护起来。

正好,通过熔断降级规则案例,来结合@SentinelResource注解一起使用。

3.5.1.引入依赖

要使用@SentinelResource方式保护资源,需要我们引入一个新的依赖,本质上注解方式底层实现是AOP

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-annotation-aspectj</artifactId>
    <version>1.8.2</version>
</dependency>

3.5.2.sentinel aop配置

/**
 * <p>
 * sentinel aop 配置
 * </p>
 *
 * @author [email protected]
 * @since 2021/8/3
 */
@Configuration
public class SentinelAspectConfiguration {
    @Bean
    public SentinelResourceAspect sentinelResourceAspect() {
        return new SentinelResourceAspect();
    }
}

3.5.3.加载降级规则

 /**
     * 初始化降级规则
     */
    public void initDegradeRules(){
        List<DegradeRule> degradeRules = Lists.newArrayList();

        DegradeRule rule = new DegradeRule();
        rule.setResource(MySentinelResource.DEGRADE_RESOURCE);// 资源
        rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);// 阈值类型:慢调用比例
        rule.setMinRequestAmount(5);// 最小请求数
        rule.setTimeWindow(1);// 熔断时长,单位秒
        rule.setSlowRatioThreshold(1);// 比例阈值
        rule.setCount(1);// 最大RT 单位 毫秒
        rule.setStatIntervalMs(1000);// 统计时长,单位毫秒

        degradeRules.add(rule);

        DegradeRuleManager.loadRules(degradeRules);

    }

3.5.4.编写资源

/**
     * 测试熔断降级规则
     * @return
     */
    @RequestMapping("degrade")
    @SentinelResource(value =MySentinelResource.DEGRADE_RESOURCE, fallback = "degradeFallback")
    public String degrade(){
        log.info("SentinelController--annotationDegrade start");
        int time = new Random().nextInt(1000);
        try {
            TimeUnit.MILLISECONDS.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("SentinelController--annotationDegrade end,耗时:{}毫秒",time);
        return "degrade ok!";
    }

   // 降级方法
    public String degradeFallback(Throwable e){
        log.error("熔断降级了,异常消息:{}", e);
        return "error!熔断降级了!";
    }

3.5.5.降级效果

请求:http://127.0.0.1:8080/sentinel/degrade?userId=1,且不断刷新

3.5.6.@SentinelResource注解说明

到此,分别通过SphU.entry,与注解@SentinelResource,实现了sentinel流控、与熔断降级的效果。我们发现@SentinelResource的方式真是好啊!代码优雅了很多!

那么对于该注解,做一个简单的说明,它的关键属性有

  • value:指定资源名称

  • blockHandler:如果是流控,用于指定发生流控后的处理方法

  • fallback:如果是降级,用于指定发生降级后的处理方法

这三个是比较常用的属性,更多属性,推荐你去看官方文档,连接地址:https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81

本文源码地址:https://gitee.com/yanghouhua/springboot.git

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章