当前位置: 首页 > article >正文

【深入理解SpringCloud微服务】Sentinel实战与原理剖析

【深入理解SpringCloud微服务】Sentinel实战与原理剖析

  • Sentinel功能
  • Sentinel三种用法
    • 硬编码
    • 注解
    • 拦截器
    • 什么时候使用注解方式,什么时候使用拦截器方式?
  • Sentinel原理

Sentinel功能

Sentinel和Hystrix一样,也是一个微服务容错保护框架,想要知道Sentinel拥有什么功能,看一下它的控制台就知道了。

在这里插入图片描述

除了流控和熔断以外,比起Hystrix还增加了热点规则、系统规则、授权规则、集群流控等功能,所有Sentinel对比Hystrix是功能更丰富的。

在这里插入图片描述

Sentinel三种用法

硬编码

引入依赖

        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-core</artifactId>
            <version>1.8.4</version>
        </dependency>

示例代码:

/**
 * @author huangjunyi
 * @date 2024/4/9 18:30
 * @desc
 */
public class SentinelDemo {

	// 注册流控规则
    static {
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        // 定义资源名称
        rule.setResource("hello");
        // QPS模式限流,每秒2个
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule.setCount(2);
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }

    private static void hello() {
        Entry entry = null;
        try {
        	// 通过SphU.entry(资源名)记录统计数据并执行给定资源的规则检查
            entry = SphU.entry("hello");
            System.out.println("hello");
        } catch (BlockException e) {
            System.out.println("限流了");
        } finally {
            if (entry != null) {
            	// 最后必须调用Entry#exit()才算完成
            	// Entry#exit()会进行一些数据的统计以及决定断路器是否打开
                entry.exit();
            }
        }
    }

    public static void main(String[] args) {
        hello();
        hello();
        // 第三次就限流了
        hello();
    }

}

执行代码后,可以看到第三次输出就流控了。
在这里插入图片描述

Sentinel的整体思路就是两步:

  1. 服务启动的时候往各种Mananger注册规则,比如以流控为例,就是往FlowRuleManager当中注册流控规则FlowRule,并且每个规则都有一个资源名称与其对应。
  2. 然后执行目标业务逻辑前先执行SphU.entry(资源名),根据资源名称从FlowRuleManager(还是以流控为例)寻找对应的FlowRule进行校验,校验通过则执行业务逻辑,校验失败则抛异常。最后还要调用entry.exit()进行收尾工作。

在这里插入图片描述

Sentinel硬编码的使用方式是最原始的使用方式,后面两种方式都是基于硬编码方式做的扩展。想要理解Sentinel的原理,首先要了解硬编码方式的实现原理。

注解

引入依赖:除了sentinel-core以外,还要引入sentinel-annotation-aspectj

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

配置类:

/**
 * @author huangjunyi
 * @date 2024/4/10 19:45
 * @desc
 */
@Configuration
public class AspectConfig {

    // 配置Sentinel的切面类,才能使@SentinelResource注解生效
    @Bean
    public SentinelResourceAspect sentinelResourceAspect() {
        return new SentinelResourceAspect();
    }

}

初始化流控规则:

/**
 * @author huangjunyi
 * @date 2024/4/8 19:06
 * @desc
 */
@Component
public class FlowRuleInit {

    @PostConstruct
    public void init() {
        initFlowRules();
    }

    // 初始化流控规则,也可以在控制台中配置
    private static void initFlowRules(){
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource("hello");
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule.setCount(2);
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }

}

Controller:

/**
 * @author huangjunyi
 * @date 2024/4/8 19:00
 * @desc
 */
@RestController
public class HelloController {

    // @SentinelResource主键指定资源名,以及降级回调方法
    @SentinelResource(value = "hello", blockHandler = "flowBlockHandler")
    @GetMapping("/hello")
    public String hello() {
        System.out.println("hello");
        return "hello";
    }

    // 被流控时的降级回调方法
    public String flowBlockHandler(BlockException blockException) {
        return "被流控了!";
    }

}

注解方式就是在目标方法上添加@SentinelResource注解,注解指定资源名称与配置的流控规则一致,流控效果就会生效。

在这里插入图片描述

如果是引入的spring-cloud-starter-alibaba-sentinel依赖,那就不需要配置Sentinel切面类了,spring-cloud-starter-alibaba-sentinel已经通过自动装配的方式帮我们配置好了。

在这里插入图片描述

拦截器

最后是拦截器的方式,这种方式是最方便的,不需要添加注解,默认是请求路径作为资源名称。

引入依赖:除了sentinel-core以外,还要引入sentinel-spring-webmvc-adapter

        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-spring-webmvc-adapter</artifactId>
            <version>1.8.4</version>
        </dependency>

配置拦截器

/**
 * @author huangjunyi
 * @date 2024/4/8 19:04
 * @desc
 */
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        SentinelWebMvcConfig config = new SentinelWebMvcConfig();
        config.setBlockExceptionHandler(new DefaultBlockExceptionHandler());
        // 设置为true,资源名称前面要带方法名,设置为false则不需要
        config.setHttpMethodSpecify(true);
        config.setWebContextUnify(true);
        config.setOriginParser(request -> request.getHeader("S-user"));
        // 添加Sentinel的拦截器
        registry.addInterceptor(new SentinelWebInterceptor(config))
                .order(Integer.MIN_VALUE)
                .addPathPatterns("/**");
    }
}

配置流控规则,或者直接在控制台配置:

/**
 * @author huangjunyi
 * @date 2024/4/8 19:06
 * @desc
 */
@Component
public class FlowRuleInit {

    @PostConstruct
    public void init() {
        initFlowRules();
    }

    // 初始化流控规则,也可以在控制台中配置
    private static void initFlowRules(){
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        // 由于拦截器的httpMethodSpecify属性配置为true,
        // 资源名称前面要带上方法名
        rule.setResource("GET:/hello");
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule.setCount(2);
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }

}

Controller:

/**
 * @author huangjunyi
 * @date 2024/4/8 19:00
 * @desc
 */
@RestController
public class HelloController {
    
    @GetMapping("/hello")
    public String hello() {
        System.out.println("hello");
        return "hello";
    }

}

使用拦截器方式,就不需要声明@SentinelResource注解了,如果通过控制台配置规则的话,甚至连上面FlowRuleInit的流控规则配置都可以不需要,只需要引入依赖jar包,然后配置一个拦截器即可。

在这里插入图片描述

Sentinel拦截器方式其实就是在拦截器SentinelWebInterceptor中执行硬编码时的模板代码。

在SentinelWebInterceptor的preHandle方法中执行SphU.entry(resourceName)方法,如果检查通过,则执行业务逻辑;检查不通过则抛出异常BlockException,SentinelWebInterceptor也会catch住异常并做相应处理。

最后SentinelWebInterceptor的afterCompletion方法会调用entry.exit()进行收尾。

在这里插入图片描述

什么时候使用注解方式,什么时候使用拦截器方式?

注解方式是网上示例最多的,但是如果我们有一百个一千个接口,难不成每个接口声明一个注解?也不是不可以,但何必这么麻烦呢?此时通过拦截器方式,默认以接口路径作为资源名称,不是更方便吗?剩下的就是在控制台配置规则。

但是拦截器方式也有注解方式做不到的地方,比如配置降级处理逻辑,以及热点参数限流。

在这里插入图片描述

这样,什么时候使用注解方式,什么时候使用拦截器方式,就很清楚了。

Sentinel原理

Sentinel底层利用了责任链模式,去处理每个不同的规则。

在这里插入图片描述

当第一次调用SphU.entry()方法时,会通过SPI机制加载指定的所有ProcessorSlot实现类,组装成一个ProcessorSlotChain,ProcessorSlotChain中每个Slot通过next指针链接形成一个单选链表。

SphU.entry()方法每次都会以责任链的方式沿着ProcessorSlotChain里的每个Slot往下执行,一旦某个Slot校验不通过,则终止不再往下,chain中的所有slot都校验通过,则返回Entry对象。

在这里插入图片描述

ProcessorSlotChain中有许多类型的Slot,我们不需要全部了解,但是有两个特别重要的我们必须要知道,一个是FlowSlot,另一个是DegradeSlot。FlowSlot对应流控规则的处理,DegradeSlot对应熔断规则的处理。它们俩一般放在chain的最末尾。

在这里插入图片描述


http://www.kler.cn/news/368767.html

相关文章:

  • STM32L476芯片在KEIL环境下BOOT跳转APP注意事项
  • 【进阶】面向对象之接口(多学三招)
  • JAVA基础:集合 (学习笔记)
  • 介绍一款Java开发的企业接口管理系统和开放平台
  • 【WPF】中Dispatcher的DispatcherPriority参数使用
  • pytorch调用手写CUDA算子和pybind11的使用
  • 重修设计模式-行为型-迭代器模式
  • 了解光耦合器输入输出关系---腾恩科技
  • 区块链国赛题目--食品溯源(模块三)
  • 租房管理智能化:Spring Boot系统开发指南
  • VMware16去虚拟化 过CF 理论过TX游戏 WIN10过检测虚拟机
  • 微信小程序SSL证书怎么选择?
  • 通过 SYSENTER/SYSEXIT指令来学习系统调用
  • 《链表篇》---环形链表
  • 数据挖掘(二)
  • Typora一款极简Markdown文档编辑器和阅读器,实时预览,序列号生成!免费!最新可用!
  • CentOS 自启动某个应用
  • IP协议详解:报头格式、主机定位、转发流程、网段划分与路由机制
  • vue通过JSON文件生成WPML文件源码
  • 关于 API
  • 【leetcode】动态规划
  • python+大数据+基于Hadoop的个性化图书推荐系统【内含源码+文档+部署教程】
  • 【我的创作纪念日1024】
  • 大数据-187 Elasticsearch - ELK 家族 Logstash Filter 插件 使用详解
  • APS开源源码解读: 排程工具 optaplanner II
  • Windows系统PyCharm右键运行.sh文件