2-3 Sentinel流控规则
1 流控规则基本介绍
1.1 名词解释
- 资源名:唯一名称,默认请求路径
- 针对来源:Sentinel可以针对调用者进行限流,填写微服务名,默认default(不区分来源)
- 阈值类型/单机阈值:
- QPS(每秒钟的请求数量):当调用该API的QPS达到阈值的时候,进行限流
- 线程数:当调用该API的线程数量达到阈值的时候,进行限流
- 是否集群:当前不需要集群
- 流控模式:
- 直接:API达到限流条件时,直接限流
- 关联:当关联的资源达到阈值时,就限流自己
- 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)(API级别的针对来源)
- 流控效果:
- 快速失败:直接失败,抛异常
- Wam Up:根据codeFactor(冷加载因子,默认3)的值,从阈值/codeFacotor,经过预热时长,才达到设置的QPS阈值
- 排队等待:匀速排队,让请求以匀速的速度通过,阈值类型必须设置为QPS,否则无效
1.2 具体操作
1.2.1 新增流控
QPS直接失败案例
- 添加有两种方式,可以直接在流控规则选项中添加,也可以在簇点链路中添加,一般会采取第二种方式
- 现在我们给"/testA"添加流控。
- 这里的意思就是我们现在单机阈值设定为1,代表的是当前这个接口只能被1秒访问一次,超过这个阈值,就会被Sentinel阻塞,现在默认为直接失败,也就是会在前台有一个体现
线程数直接失败案例
- 刚才我们可以的设置是通过QPS(每秒钟请求的数量)来设置的限流规则,但是我们这里其实还有一个线程数,是什么意思那?
- QPS和并发线程数规则详解
- 那我们要演示这种效果,我们就需要让一个线程再进来办理的时候需要0.8秒,但是这个时候后面的线程也在疯狂的访问,所以后面的线程就会不会生效。
package com.example.cloudalibabasentinel8401.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit;
@RestController
public class FlowLimitController {
@GetMapping("/testA")
public String testA(){
//暂停0.8秒
try {
TimeUnit.MILLISECONDS.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "-----testA";
}
@GetMapping("/testB")
public String testB(){
return "-----testB";
}
}
- 这个时候我们重启项目,然后重新通过访问testA接口,通过两个网页(线程)来快速访问,这个时候我们来看效果,这里要注意,要重新添加流控规则。
注意:这个时候虽然效果一致,但是是两种完全不同的规则,一种是QPS,一种是并发线程,这点大家一定要分清!
2 流控规则-关联
首先我们先来回顾一下之前讲过的一些概念
2.1 名词解释
- 资源名:唯一名称,默认请求路径
- 针对来源:Sentinel可以针对调用者进行限流,填写微服务名,默认default(不区分来源)
- 阈值类型/单机阈值:
- QPS(每秒钟的请求数量):当调用该API的QPS达到阈值的时候,进行限流
- 线程数:当调用该API的线程数量达到阈值的时候,进行限流
- 是否集群:当前不需要集群
- 流控模式:
- 直接:API达到限流条件时,直接限流
- 关联:当关联的资源达到阈值时,就限流自己
- 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)(API级别的针对来源)
- 流控效果:
- 快速失败:直接失败,抛异常
- Wam Up:根据codeFactor(冷加载因子,默认3)的值,从阈值/codeFacotor,经过预热时长,才达到设置的QPS阈值
- 排队等待:匀速排队,让请求以匀速的速度通过,阈值类型必须设置为QPS,否则无效
2.2 关联
官方解释:当关联的资源达到阈值时,就限流自己。
通俗解释来说,比如那我们的程序,现在有testA接口和testB接口,当A关联的资源B达到阈值后,就限流自己,也就是B到达阈值,限流A本身。就好像我家孩子在外面打架,我来处理一样。换到程序里面来说比如一个电商系统中,支付系统达到阈值,就限流下订单系统。
2.3 具体演示
当关联资源**/testB的qps阈值超时1时,就限流/testA**的Rest访问地址,当关联资源到阈值后限制配置好的资源名,首先我们先把FlowLimitController接口恢复原样
@RestController
public class FlowLimitController {
@GetMapping("/testA")
public String testA(){
return "-----testA";
}
@GetMapping("/testB")
public String testB(){
return "-----testB";
}
}
给testA添加流控规则
为了演示效果,所以这里我们需要借助一个工具Postman,来模仿并发密集访问/testB,先来测试访问testB接口
这个时候我们需要多次密集访问TestB接口,所以我们需要添加配置,具体操作如下:
把数值修改为:
- Iterations:为20
- Delay:300
意思就是20个线程每间隔0.3秒访问一次,然后跑起来
这个时候我们来看网页中testA接口的效果
3 流控规则-链路
3.1 名词解释
- 资源名:唯一名称,默认请求路径
- 针对来源:Sentinel可以针对调用者进行限流,填写微服务名,默认default(不区分来源)
- 阈值类型/单机阈值:
- QPS(每秒钟的请求数量):当调用该API的QPS达到阈值的时候,进行限流
- 线程数:当调用该API的线程数量达到阈值的时候,进行限流
- 是否集群:当前不需要集群
- 流控模式:
- 直接:API达到限流条件时,直接限流
- 关联:当关联的资源达到阈值时,就限流自己
- 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)(API级别的针对来源)
- 流控效果:
- 快速失败:直接失败,抛异常
- Wam Up:根据coldFactor(冷加载因子,默认3)的值,从阈值/codeFacotor,经过预热时长,才达到设置的QPS阈值
- 排队等待:匀速排队,让请求以匀速的速度通过,阈值类型必须设置为QPS,否则无效
3.2 链路
链路流控模式指的是,当从某个接口过来的资源达到限流条件时,开启限流,它的功能有点类似于针对来源配置项,区别在于:针对来源是针对上级微服务,而链路流控是针对上级接口,也就是说它的粒度更细。
比如在一个微服务中,两个接口都调用了同一个Service中的方法,并且该方法用SentinelResource(用于定义资源)注解标注了,然后对该注解标注的资源(方法)进行配置,则可以选择链路模式。
3.3 具体演示
首先我们编写一个Service
//service.TestService
@Service
public class TestService {
// 定义限流资源
@SentinelResource("common")
public String common(){
return "common";
}
}
然后更改接口调用这个Service方法
@RestController
public class FlowLimitController {
@Autowired
TestService testService;
@GetMapping("/testA")
public String testA(){
return testService.common();
}
@GetMapping("/testB")
public String testB(){
return testService.common();
}
}
接下来配置流控规则:
这里要注意不要对/testA或者/testB进行限流规则的配置,要给用SentinelResource注解标注的资源进行配置限流规则,这里的意思为当我们用入口资源访问被SentinelResource注解标注的资源方法时,当超过阈值就会被限流。
注意:如果版本为,或以上:
<spring-cloud-alibaba-version>2.2.5.RELEASE</spring-cloud-alibaba-version>
不需要在设置web-context-unify
4 Sentinel流控效果-预热
4.1 名词解释
- 资源名:唯一名称,默认请求路径
- 针对来源:Sentinel可以针对调用者进行限流,填写微服务名,默认default(不区分来源)
- 阈值类型/单机阈值:
- QPS(每秒钟的请求数量):当调用该API的QPS达到阈值的时候,进行限流
- 线程数:当调用该API的线程数量达到阈值的时候,进行限流
- 是否集群:当前不需要集群
- 流控模式:
- 直接:API达到限流条件时,直接限流
- 关联:当关联的资源达到阈值时,就限流自己
- 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)(API级别的针对来源)
- 流控效果:
- 快速失败:直接失败,抛异常
- Warm Up:根据coldFactor(冷加载因子,默认3)的值,从阈值/codeFacotor,经过预热时长,才达到设置的QPS阈值
- 排队等待:匀速排队,让请求以匀速的速度通过,阈值类型必须设置为QPS,否则无效
4.2 预热
官网手册地址:https://sentinelguard.io/zh-cn/docs/flow-control.html
概念:Warm Up方式,即预热/冷启动方式。该方式主要用于系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮的情况。
预热公式:阈值/coldFactor(默认值为3),经过预热时间后才会达到阈值。
冷启动的过程系统允许通过的QPS曲线如下图:
简单理解:
使用场景:一般秒杀系统中会有这样的流控设置,为了防止秒杀瞬间造成系统崩溃。
4.3 案例
默认coldFactor为3,当发起请求即请求QPS从(阈值/3)开始,经过多长预热时长才逐步升至设定的QPS阈值,当前阈值设置为10,预热时长设置为5秒。
最终的效果,系统初始化时阈值/3约等于3,即阈值在此时为3,经过5秒后阈值才慢慢升高到10
首先我们先来设置流控效果:
测试,我们用最简单的方法进行测试,直接在浏览器上手动刷新,然后我们来看Sentinel的实时监控
5 Sentinel流控效果-排队等待
5.1 名词解释
- 资源名:唯一名称,默认请求路径
- 针对来源:Sentinel可以针对调用者进行限流,填写微服务名,默认default(不区分来源)
- 阈值类型/单机阈值:
- QPS(每秒钟的请求数量):当调用该API的QPS达到阈值的时候,进行限流
- 线程数:当调用该API的线程数量达到阈值的时候,进行限流
- 是否集群:当前不需要集群
- 流控模式:
- 直接:API达到限流条件时,直接限流
- 关联:当关联的资源达到阈值时,就限流自己
- 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)(API级别的针对来源)
- 流控效果:
- 快速失败:直接失败,抛异常
- Warm Up:根据coldFactor(冷加载因子,默认3)的值,从阈值/codeFacotor,经过预热时长,才达到设置的QPS阈值
- 排队等待(匀速器):匀速排队,让请求以匀速的速度通过,阈值类型必须设置为QPS,否则无效
5.2 排队等待
官方文档:https://sentinelguard.io/zh-cn/docs/flow-control.html
概念:匀速排队方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。
这种方式主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求(削峰填谷)。
例图:
5.2.1 匀速器
它的中心思想是,以固定的间隔时间让请求通过。当请求到来的时候,如果当前请求距离上个通过的请求通过的时间间隔不小于预设值,则让当前请求通过。否则,计算当前请求的预期通过时间,如果该请求的预期通过时间小于规则预设的 timeout 时间,则该请求会等待直到预设时间到来通过(排队等待处理);若预期的通过时间超出最大排队时长,则直接拒接这个请求。
Sentinel 匀速排队等待策略是漏桶算法结合虚拟队列等待机制实现的。
注意:匀速排队模式暂时不支持 QPS > 1000 的场景。
5.3 演示
流控规则:
为了看到效果,我们在代码中进行打印,更改8401微服务中的FlowLimitController
package com.example.cloudalibabasentinel8401.controller;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.example.cloudalibabasentinel8401.service.TestService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit;
@RestController
@Slf4j
public class FlowLimitController {
@Autowired
TestService testService;
@GetMapping("/testA")
public String testA(){
log.info(Thread.currentThread().getName()+":testA");
return testService.common();
}
@GetMapping("/testB")
public String testB(){
return testService.common();
}
}
最后我们可以通过Postman来进行测试,发送请求时没有延迟,同时发送10条请求,然后我们会发现就是排队效果1秒执行一个请求,同时我们在Idea中也可以看到打桩效果
评论区