Sentinel五大规则学习


本次演示以sentinel 1.8.0版本为例,讲解sentinel中流控、降级、热点、系统、授权五大规则。

在这里插入图片描述

一、流控规则

流量控制,其原理是监控应用流量的QPS(每秒查询率) 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。

请添加图片描述

资源名:接口路径名

针对来源:指定对哪个微服务进行限流,默认指default,意思是不区分来源,全部限制

阈值类型和单机阈值:

  • QPS(每秒请求数量):: 当调用该接口的QPS达到阈值的时候,进行限流
  • 线程数:当调用该接口的线程数达到阈值的时候,进行限流

是否集群:暂不需要集群

流控模式:

  • 直接:直接流控模式是最简单的模式,当指定的接口达到限流条件时开启限流。
  • 关联:当指定接口关联的接口达到限流条件时,对指定接口开启限流。
  • 链路:A、B接口都在调用C接口,A、B接口谁调用C达到限流条件就限流谁。

流控效果:

  • 快速失败(默认):直接失败,抛出异常,不做任何额外的处理,是最简单的效果。
  • Warm Up:它从开始阈值到最大QPS阈值会有一个缓冲阶段,一开始的阈值是最大QPS阈值的 1/3,然后慢慢增长,直到最大阈值,适用于将突然增大的流量转换为缓步增长的场景。
  • 排队等待:让请求以均匀的速度通过,单机阈值为每秒通过数量,其余的排队等待; 它还会让设置一个超时时间,当请求超过超时间时间还未处理,则会被丢弃。

主要演示三种流控模式,演示之前工作:

导入sentinel依赖:

<!-- SpringBoot 整合 nacos-sentinel 持久化 -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
    <version>1.8.0</version>
</dependency>

配置文件:

server:
  port: 8080

spring:
  application:
    name: mumber-producer #服务名程

  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # nacos默认端口地址为8848
        enabled: true
    sentinel:
      transport:
        dashboard: localhost:8718  #sentinel-dashboard 地址
      eager: true
      web-context-unify: false #关闭context整合

开启sentinel控制台:

#jar命令启动,自定义端口号(控制台本身是一个SpringBoot项目)    
java -Dserver.port=8718 -Dcsp.sentinel.dashboard.server=localhost:8718 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.0.jar

启动mumber-producer服务注册到控制台

在这里插入图片描述

1 直接模式

直接流控模式是最简单的模式,当指定的接口达到限流条件时开启限流。

  1. java代码
@RestController
@Slf4j
public class MumberController1 {
    
    @RequestMapping("/message1")
    @SentinelResource(value = "message1", blockHandler = "insertUserBlockHandler")
    public String message1() {
        return "message1" + "";
    }
}

/**
 * blockHandler为自定义的提示方法
 * 必须为public、返回类型、参数类型与原方法一致,额外加一个BlockException参数
 * @return
 */
public String insertUserBlockHandler(BlockException e){
    return "当前访问人数太多,请稍后重试!";
}
  1. 添加直接规则

在这里插入图片描述

  1. 访问接口测试

http://localhost:8080/message1

在这里插入图片描述

当每秒请求次数超过1次时,会进行限流。


2 关联模式

当指定接口关联的接口达到限流条件时,对指定接口开启限流。(孩子惹事,家长负责)

  1. java代码
@RestController
@Slf4j
public class MumberController1 {
    
    @RequestMapping("/message1")
    @SentinelResource(value = "message1", blockHandler = "insertUserBlockHandler")
    public String message1() {
        return "message1接口..." + "";
    }

    @RequestMapping("/message2")
    @SentinelResource(value = "message2", blockHandler = "insertUserBlockHandler")
    public String message2() {
        return "message2接口...";
    }

    /**
     * blockHandler为自定义的提示方法
     * 必须为public、返回类型、参数类型与原方法一致,额外加一个BlockException参数
     * @return
     */
    public String insertUserBlockHandler(BlockException e){
        return "当前访问人数太多,请稍后重试!";
    }

}

  1. 添加关联规则

在这里插入图片描述

  1. 访问测试

单独访问message1、message2都不会达到限流,只有频繁访问message2(超过每秒1次时),再去访问message1,则message1会限流。


3 链路模式

当A、B接口两个接口都在调用C接口,A、B接口谁调用C达到限流条件就限流谁,另一个接口不受影响。

  1. java代码
@Service
@Slf4j
public class MumberServiceImpl {

    @SentinelResource(value = "message")
    public void message() {
        log.info("--->message");
    }
}
@RestController
@Slf4j
public class MumberController1 {

    @Autowired
    private MumberServiceImpl mumberServiceImpl;

    @RequestMapping("/message1")
    @SentinelResource(value = "message1", blockHandler = "insertUserBlockHandler")
    public String message1() {
        String message = mumberServiceImpl.message();
        return "message1接口..." + "调用了" + message;
    }

    @RequestMapping("/message2")
    @SentinelResource(value = "message2", blockHandler = "insertUserBlockHandler")
    public String message2() {
        String message = mumberServiceImpl.message();
        return "message2接口..." + "调用了" + message;
    }

    /**
     * blockHandler为自定义的提示方法
     * 必须为public、返回类型、参数类型与原方法一致,额外加一个BlockException参数
     * @return
     */
    public String insertUserBlockHandler(BlockException e){
        return "当前访问人数太多,请稍后重试!";
    }

}
  1. 添加配置
server:
  port: 8080

spring:
  application:
    name: mumber-producer #服务名程

  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # nacos默认端口地址为8848
        enabled: true
    sentinel:
      transport:
        dashboard: localhost:8718  #sentinel-dashboard 地址
      eager: true
      #添加这行配置
      web-context-unify: false #关闭context整合
  1. 添加链路规则

在这里插入图片描述

理论上此时通过message2调用message接口不受影响,通过message1调用message接口则会限流。

但此处遇到一个bug,频繁访问message1接口时控制台报错:

在这里插入图片描述

百度许久依旧没有找到答案,后期如果解决了我会及时更新这篇笔记以及贴出解决方案。


二、降级规则

在这里插入图片描述

资源名:接口路径名

熔断策略:

  • 慢调用比例(以前的版本也叫RT):选择一个慢调用比例作为阈值。

    引入一个场景:A模块调用B模块

    • 最大RT:Response Time 最大响应时间,即A调用B,B超过这个时间响应即为慢调用。
    • 比例阈值:百分比,即访问接口慢调用达到百分之多少时,采用服务降级。
    • 熔断时长:即触发熔断后,熔断持续的时长,如A调用B,B响应太慢,因此A模块采用降级处理,在一个时间段之内不会重复调用B。超过这个时间段过后再进行调用。
    • 最小请求数:熔断触发的最小请求数(避免1次2次偶尔响应时间慢就开启降级处理,没必要)。
  • 异常比例:

    • 比例阈值:百分比,即访问接口异常达到百分之多少时,采用服务降级。
    • 熔断时长:即触发熔断后,熔断持续的时长。
    • 最小请求数:熔断触发的最小请求数。
  • 异常数:

    • 异常数:访问接口异常的次数达到多少触发熔断处理。
    • 熔断时长:与上面一致。
    • 最小请求数:与上面一致。

现对三种降级策略开启演示:

1 慢调用比例

  1. java代码
@Service
@Slf4j
public class MumberServiceImpl {

    public String message(int id) {
        if (id % 2 == 0){
            try {
                Thread.sleep(500); //当传递过来的参数为偶数时,休眠500毫秒实现慢调用
            } catch (Exception e){
                e.printStackTrace();
            }
            return "slow message";
        }
        return "fast message";
    }

}
@RestController
@Slf4j
public class MumberController1 {

    @Autowired
    private MumberServiceImpl mumberServiceImpl;
    /**
     * 降级策略---慢调用比例
     */
    @GetMapping("/getMessage")
    @SentinelResource(value = "getMessage", blockHandler = "insertUserBlockHandler")
    public String getMessage(@RequestParam("id") int id){
        log.info("--->:{}" + id);
        return mumberServiceImpl.Message(id);
    }
    
    /**
     * blockHandler为自定义的提示方法
     * 必须为public、返回类型、参数类型与原方法一致,额外加一个BlockException参数
     * @return
     */
    public static String insertUserBlockHandler(int id,BlockException e){
        return "当前访问人数太多,请稍后重试!" ;
    }

}
  1. 新增熔断降级

在这里插入图片描述

  1. 测试接口

localhost:8080/getMessage?id=2

携带偶数参数连续访问的接口占比50%时,会触发降级处理:在这里插入图片描述
localhost:8080/getMessage?id=1

携带奇数参数时不受限制:
在这里插入图片描述


2 异常比例

  1. java代码
@Service
@Slf4j
public class MumberServiceImpl {
    public String Message(int id) {
        if (id % 2 == 0){
            int i = 3 / 0; //人为构造一个异常
            return "异常 message";
        }
        return "普通 message";
    }

}
@RestController
@Slf4j
public class MumberController1 {

    @Autowired
    private MumberServiceImpl mumberServiceImpl;
    /**
     * 降级策略---异常比例
     */
    @GetMapping("/getMessage")
    @SentinelResource(value = "getMessage", blockHandler = "getMessageException")
    public String getMessage(@RequestParam("id") int id){
        log.info("--->:{}" + id);
        return mumberServiceImpl.Message(id);
    }
    
    /**
     * blockHandler为自定义的提示方法
     * 必须为public、返回类型、参数类型与原方法一致,额外加一个BlockException参数
     * @return
     */
    public static String getMessageException(int id, BlockException e){
        return "访问接口异常,请稍后重试!" ;
    }

}
  1. 添加异常比例

请添加图片描述

  1. 测试

当携带参数为偶数时,会触发异常,当访问这个异常接口占比达到50%时会降级处理。

localhost:8080/getMessage?id=2

携带偶数参数连续访问的接口占比50%时,会触发降级处理:
请添加图片描述

localhost:8080/getMessage?id=1

携带奇数参数时不受限制:
请添加图片描述


3 异常数,与异常比例类似,此处不再演示,读者一看就会。

请添加图片描述


三、热点规则

在进行RESTful 设计的时候,一般都需要在 Action 的处理方法中进行请求参数的接收,于是这个时候可以针对于参数进行限流,这种规则就称为热点规则。

热点参数流控规则是一种更细粒度的流控规则, 它允许将规则具体到参数上。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WNnRXjKp-1670498950020)(D:\笔记\sentinel\热点规则.png)]

资源名:接口路径名

参数索引:一般接口都有参数,从接口的第一个参数开始,以0为下标累加,每个参数都有一个下标。每个接口独立计算。

单机阈值:接口每秒的访问数。

统计窗口时长:限流接口的时效。

是否集群:默认不集群。

参数例外项:参数例外项就是可以达到更加细粒度的控制,比如我们的某个被设置为限流的参数,可以通过参数例外项设置参数具体等于某个特殊的值的时候,触发不同的限流效果。例如有参数userId,普通设置为一个阈值,当userId等于某个具体的数时,设置特殊阈值。

代码演示:

  1. java代码
@RestController
@Slf4j
public class MumberController2 {

    @RequestMapping("/user")
    @SentinelResource(value = "user", blockHandler = "fail")
    //此处age设置为Integer而非int,目的是Integer可以为null,而int不行
    public String user(String name,Integer age) {
        return "姓名:" +name + "---" + "年龄:" + age;
    }

    /**
     * blockHandler为自定义的提示方法
     * @return
     */
    public String fail(String name,Integer age, BlockException e){
        return "接口参数被限流了,请稍后重试!" ;
    }

}
  1. 添加限流规则

请添加图片描述

  1. 访问测试

频繁访问限流的接口:localhost:8080/user?name=zhnagsan

请添加图片描述

频繁访问未被限流的接口:localhost:8080/user?age=20,无论怎么访问,都没有限流提示。

请添加图片描述

  1. 修改user接口第一个参数限流的参数例外项,当name为zhangsan时,限流阈值修改为3(每秒允许访问3次,超过则限流)

请添加图片描述

再次频繁访问限流的接口:localhost:8080/user?name=zhnagsan,发现限流速度比刚才慢了。


四、系统规则

请添加图片描述

系统保护规则是从应用级别的入口流量进行控制,从单台机器的总体 Load、RT、入口 QPS 、CPU使用率和线程数五个维度监控应用数据,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量 (进入应用的流量) 生效。

  • Load(仅对 Linux/Unix-like 机器生效):当系统 load1 超过阈值,且系统当前的并发线程数超过 系统容量时才会触发系统保护。系统容量由系统的 maxQps * minRt 计算得出。设定参考值一般 是 CPU cores * 2.5。
  • RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
  • 线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
  • 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
  • CPU使用率:当单台机器上所有入口流量的 CPU使用率达到阈值即触发系统保护

此处直接贴出alibaba sentinel官方的介绍,通俗易懂,就不演示实现了。


五、授权规则

授权规则可以对请求方来源做判断和控制。

  • 白名单:来源(origin)在白名单内的调用者允许访问
  • 黑名单:来源(origin)在黑名单内的调用者不允许访问

请添加图片描述

资源名:接口名

流控应用:是来源者的名单。

代码演示:

  1. java代码

首先新建一个RequestOriginParser的实现类,Sentinel是通过RequestOriginParser这个接口的parseOrigin来获取请求的来源的。

@Component
@Slf4j
public class RequestOriginParserDefinition implements RequestOriginParser {

    @Override
    public String parseOrigin(HttpServletRequest request) {
        String serviceName = request.getParameter("serviceName"); //接收请求参数
        if (serviceName == null || "".equals("serviceName")){ //如果参数内容为空
            serviceName = request.getHeader("serviceName");
        }
        log.info("授权信息serviceName--->" + serviceName);
        if (StringUtils.isEmpty(serviceName)){
            return request.getRemoteAddr(); //根据ip地址处理
        }
        return serviceName;
    }
}
@RequestMapping("/message1")
@SentinelResource(value = "message1", blockHandler = "insertUserBlockHandler")
public String message1() {
    String message = mumberServiceImpl.message();
    return "message1接口..." + "调用了" + message;
}

对于message1这个接口调用mumberServiceImpl的message()接口,在没有配置授权规则时,是能正常访问的。
请添加图片描述

  1. 配置授权规则

请添加图片描述

  1. 采用postMan工具测试,为该接口参数serviceName设置配置的值admin

请添加图片描述

  1. 此处只是采用postman进行了简单的测试,在实际开发中,比如A服务调用B服务的某个接口,是不可能采用postman手动携带参数的,需要在接口中携带参数信息。
GitHub 加速计划 / sentine / Sentinel
36
7
下载
alibaba/Sentinel: Sentinel 是阿里巴巴开源的一款面向分布式服务架构的流量控制、熔断降级组件,提供实时监控、限流、降级和系统保护功能,适用于微服务治理场景。
最近提交(Master分支:17 天前 )
4a419818 * Improved Date formatter * change in naming conv * change in datetime format * Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> 9 天前
d9398b4f 10 天前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐