Sentinel限流规则详解

扫测资讯 2024-07-27 00:07   22 0

上一期教程讲解了 Sentinel 的快速入门: Sentinel快速入门 ,这一期主要讲述 Sentinel 的 限流规则

簇点链路

簇点链路就是项目内的调用链路(Controller -> Service -> Mapper),链路中被监控的每个接口就是一个资源。默认情况下 Sentinel 会监控 SpringMVC 的每一个 端点(Endpoint) ,因此 SpringMVC 的每一个端点(Endpoint)就是调用链路中的一个资源 (这里指的就是 Controller 中的方法)

流控、熔断等都是 针对簇点链路中的资源 来设置的,因此我们可以点击对应资源后面的按钮来设置规则:

点击后面的流控按钮,就可以弹出表单。表单中可以添加流控规则,如下图所示:

然后,我们在单击阈值的框中填写数字 1 并点击新增按钮,表示限制 /service1/hello 这个资源的单击 QPS 为1,即每秒只允许1次请求,超出的请求会被拦截并报错

之后在浏览器快速刷新对应的页面,结果如下所示,表示限流规则已经生效

流控模式

在添加限流规则时,点击高级选项,可以选择三种流控模式:

三种模式对应的含义是:

1. 直接

统计当前资源的请求,触发阈值时对当前资源直接限流,是默认的模式

2. 关联

统计与当前资源相关的另一个资源,当另一个资源触发阈值时,对当前资源限流

使用场景:用户支付时需要修改订单状态,同时用户要查询订单。查询和修改操作会争抢数据库锁,产生竞争。业务需求是优先支付和更新订单的业务,因此当修改订单业务触发阈值时,需要对查询订单业务限流

例如,对于下图来说,当 /write 资源访问量触发阈值时,就会对 /read 资源限流,避免影响 /write 资源

一般来说,满足下面条件就可以使用关联模式:

① 两个有竞争关系的资源
② 一个优先级较高,一个优先级较低

3.链路

统计从指定链路访问到本资源的请求,触发阈值时,对指定链路限流

例如,有两条请求链路:

/link1 -> /common
/link2 -> /common

如果只希望统计从 /link2 进入到 /common 的请求,就可以设置链路模式的流控规则

实现步骤:

1.在服务层中填写共同调用的方法

@Service
public class WebServiceImpl implements WebService {

    @Override
    @SentinelResource("/common")
    public void common() {
        System.out.println("调用共同方法");
    }

}

需要注意的是,Sentinel 默认只标记 Controller 中的方法作为资源,如果要标记其它方法,需要利用 @SentinelResource 注解进行标记,参数为对应资源的路径

2.在控制层中,编写两条请求链路方法

@RestController
@RequestMapping("/service1")
public class WebController {

    @Autowired
    private WebService service;

    @GetMapping("/link1")
    public String link1() {
        service.common();
        return "调用链路1";
    }

    @GetMapping("/link2")
    public String link2() {
        service.common();
        return "调用链路2";
    }

}

3.修改配置文件

Sentinel 默认会将 Controller 中所有的方法进行 context 整合,此时会认为所有的 Controller 端点是同一个根链路发展而来的两个子链路,那么最终还是属于一个链路,由于不是两个链路,因此会导致链路模式的流控失效

如下图所示:

此时需要在 application.yml 添加:

spring:
  cloud:
    sentinel:
      web-context-unify: false # 关闭context整合

重新启动后,可以发现变成了两个链路,如下图所示:

4.在控制台设置流控规则,限制从 /service1/link2 进入到 /common 的 QPS 阈值为 2

5.测试

快速在浏览器刷新 link2 的请求,可以得到如下结果,即流控规则已经生效

流控效果

流控效果是指请求达到流控阈值时应该采取的措施,包括三种:

1.快速失败

达到阈值后,新的请求会被立即拒绝并抛出 FlowException 异常。是默认的处理方式

2.wam up

预热模式,对超出阈值的请求同样是拒绝并抛出异常。但这种模式阈值会动态变化,从一个较小值逐渐增加到最大阈值

warm up 是应对服务冷启动(冷启动指的是服务器虽然具有某一 QPS 最大值,但在刚启动时,是无法达到这个最大值的,如果此时请求数较高,即使没有超过最大QPS,服务器也可能因此挂掉)的一种方案。请求阈值初始值是 threshold / coldFactor ,threshold 是最大阈值,coldFactor 是冷启动因子。持续指定时长后,逐渐提高到 threshold 值。而 coldFactor 的默认值是 3

3.排队等待

让所有的请求按照先后次序排队执行,两个请求的间隔不能小于指定时长

在排队等待中,所有请求都会进入一个队列中,然后按照阈值允许的时间间隔依次执行。后来的请求必须等待前面执行完成,如果请求的等待时间超出最大时长,则会被拒绝

例如,如果 QPS = 5,意味着每 200ms 处理一个队列中的请求;而如果此时 timeout = 2000,则意味着等待超过 2000ms 的请求会被拒绝并抛出异常

这种效果的好处是,即使请求数量的波动较大,即某段时间请求数量很少,某段时间请求数量很多,从队列中出去的数量也会是稳定的。因此起到流量削峰的作用,对微服务具有一定的保护功能

热点参数限流

之前的限流是统计访问某个资源的所有请求,判断是否超过 QPS 阈值。而热点参数限流是分别统计 参数值相同 的请求,判断是否超过 QPS 阈值。这种方式是一种粒度更细的限流,精细到参数级别

例如,在下图中,有四个请求,其中三个请求的参数 id 为1,最后一个请求的参数 id 为 2。此时就可以得出,id 为 1 的 QPS 为 3,id 为 2 的 QPS 为1

案例:

1.编写控制层代码

这里需要注意的是,热点参数限流对默认的 SpringMVC 资源无效,只有通过 @SentinelResource 注解声明的资源才有效

@RestController
@RequestMapping("/service1")
public class WebController {

    @GetMapping("/hot")
    @SentinelResource("/hot")
    public String hot(String username, String password, Integer age) {
        return "热点";
    }

}

2.在控制台中编写热点规则

该配置代表的含义是,对 /hot 这个资源的第 0 号参数(即第一个参数)做统计,每 10s 相同参数值的请求数不能超过 1

点击高级选项,可以对部分参数进行例外配置。如下图所示

结合之前的配置,表示对第一个参数限流,每 10s 相同参数的 QPS 不能超过 1,但有两个例外:

① 如果参数类型是 String 且 参数值是 123456,则每 1 秒允许的 QPS 为 2
② 如果参数类型是 int 且 参数值是 20,则每 1 秒允许的 QPS 为 3

3.测试

在浏览器输入: localhost:8081/service1/hot?username=张三&password=123456&age=20

测试点主要有三个:

① 快速刷新浏览器,此时结果应为刷新到第二次时就会报错
② 将参数索引修改为 1,此时结果应为刷新到第三次时就会报错
③ 将参数索引修改为 2,此时结果应为刷新到第四次时就会报错