微服务系列:Spring Cloud Alibaba 之 Sentinel 高级流控规则
微服务系列:Spring Cloud Alibaba 之 Sentinel 基本流控规则在上一篇中,我们学习完了 Sentinel 的基本流控规则,这篇我们来研究一下 Sentinel 的高级流控规则。话不多说,开始今天的学习。一、概述控制台打开流控规则的高级选项如下出现了 流控模式 和 流控效果 配置选项,这些配置项都是什么意思呢?流控模式:直接:api 达到限流条件时,直接限流关联:当关联的资
在上一篇中,我们学习完了 Sentinel
的基本流控规则,这篇我们来研究一下 Sentinel
的高级流控规则。
话不多说,开始今天的学习。
一、概述
控制台打开流控规则的高级选项如下
出现了 流控模式 和 流控效果 配置选项,这些配置项都是什么意思呢?
-
流控模式:
- 直接:api 达到限流条件时,直接限流
- 关联:当关联的资源达到限流阈值时,就限流自己
- 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到峰值,就进行限流)【api级别的针对来源】
-
流控效果:
- 快速失败:直接失败,抛异常
- Warm Up:根据coldFactor(冷加载因子,默认3)的值,从阈值/coldFactor,经过预热时长,才达到设置的QPS阈值
- 排队等待:匀速排队,让请求以匀速通过,阈值类型必须设置为QPS,否则无效
接下来,让我们详细研究一下。
二、流控模式
1. 直接
api 达到限流条件时,直接限流
这个没什么好说的,直接 + 快速失败
是默认的流控模式,在微服务系列:Spring Cloud Alibaba 之 Sentinel 基本流控规则 这篇中,我们的案例就是使用的这种默认的流控模式。
2. 关联
当关联的资源达到限流阈值时,就限流自己
假设 testA
关联 testB
,当与 A 关联的资源 B 达到阈值后,就限流 A 自己,比如支付接口达到阈值时,就去限流下订单接口
@RestController
public class TestController {
@GetMapping("/testA")
public String testA(){
return "testA....";
}
@GetMapping("/testB")
public Object testB(){
return "testB......";
}
}
我们在控制台中这样配置
保存之后,我们浏览器访问地址 localhost:9201/testA 和 localhost:9201/testB 发现都是正常返回,没有问题,此时我们就要借助工具来模拟了
这里我们使用 postman
来测试,原理是使用 postman
启动一个 runner 来不停的访问着 /testB
接口,使 /testB
资源处于达到阈值的状态,然后我们再浏览器访问 /testA
,就会触发 /testA
的限流,当 /testB
恢复到没有达到阈值的状态时,/testA
访问恢复正常,不再触发限流。
注意:这里 /testB 达到阈值,/testB 并不会请求失败,只是给 /testA 的一种状态
- postman 中新增一个 collections ,加入一个访问 /testB 请求
- 点击 Run
- 设置循环 50 次,间隔时间是 1 毫秒
- 点击启动,同时赶紧去浏览器访问 localhost:9201/testA
/testA
触发限流
等 postman 中的 /testB 执行完之后,/testA 接口恢复正常
3. 链路
只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到峰值,就进行限流)
它的功能有点类似于针对来源配置项,区别在于:针对来源是针对上级微服务,而链路流控是针对上级接口,也就是说它的粒度更细。
直接看概念可能不太好理解,我们直接上案例:
3.1、两个接口同时调用资源 testC
@RestController
public class TestController {
@Autowired
private ITestServiceImpl testService;
@GetMapping("/testA")
public String testA(){
return testService.testC();
}
@GetMapping("/testB")
public Object testB(){
return testService.testC();
}
}
3.2、@SentinelResource
定义资源 testC
public interface ITestService {
String testC();
}
@Service
public class ITestServiceImpl implements ITestService {
@Override
@SentinelResource(value = "testC", blockHandler = "testCBlockHandler")
public String testC() {
return "调用 testC 资源";
}
public String testCBlockHandler(BlockException ex)
{
return "testC 触发限流...........";
}
}
3.3、配置文件:禁止收敛URL的入口 context
spring:
cloud:
sentinel:
web-context-unify: false # 关闭 context 整合
说实话这里有个坑,低版本可能不生效
从1.6.3 版本开始,Sentinel Web filter 默认收敛所有URL的入口 context,因此链路限流不生效。
1.7.0 版本开始(对应SCA的2.1.1.RELEASE),官方在 CommonFilter 引入了WEB_CONTEXT_UNIFY 参数,用于控制是否收敛context。将其配置为 false 即可根据不同的URL 进行链路限流。
本篇文章使用的 SCA 是 2.2.5 版本,也就是可以直接用这个 web-context-unify: false
来使链路限流生效
<spring-cloud-alibabersion>2.2.5.RELEASE</spring-cloud-alibaba.version>
3.4、启动项目测试
启动项目,访问一下 localhost:9201/testA 地址,观察控制台
树状视图下,可以看到资源 /testA
调用了资源 testC
,此时我们给资源 testC
添加链路限流规则
意思是,从入口资源 /testA
调用资源 testC
一旦超过阈值,则触发限流
我们来测试一下,浏览器快速刷新 localhost:9201/testA 地址,触发限流
快速刷新 localhost:9201/testB ,不触发限流
注:
虽然在树状视图下显示有两个 testC
资源,但其实是一个,切回列表视图看看
三、流控效果
1. 快速失败
快速失败是默认效果,即当触发限流时,立即抛出异常 FlowException
,立即失败。
2. Warm Up
Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。
设置阈值为 10 ,预热时间是 5 秒,逐渐增加到阈值上限,所以会有一个初始阈值
初始阈值 = 阈值上限 / coldFactor, coldFactor 是冷加载因子,默认为3
上面这个配置的效果就是:在 5 秒内最大阈值是 3(10/codeFactor),超过5秒,最大阈值为10
浏览器快速刷新 localhost:9201/testA 地址,5 秒内会出现限流,5 秒之后阈值上升为 10
注意:
是每次从流量进来时候都会开始"冷启动",也就是一波请求访问完之后,中间间隔了点时间,再来一波请求同样会重新开始冷启动
3. 排队等待
匀速排队,让请求以匀速通过,阈值类型必须设置为QPS,否则无效
排队等待方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。
这种方式主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。
注意:匀速排队模式暂时不支持 QPS > 1000 的场景。
testA
接口打印日志
@GetMapping("/testA")
public String testA(){
log.info(Thread.currentThread().getName() + "\t" + "testA......");
return "testA....";
}
控制台设置排队等待规则
当阈值设为 2 的时候,则代表一秒匀速的通过 2 个请求,也就是每个请求平均间隔恒定为 1000 / 2 = 500 ms
,每一个请求的最长等待时间(maxQueueingTimeMs
)为 1s 。
快速访问地址 localhost:9201/testA,观察控制台日志,每秒确实匀速通过两个请求
但这个 超时时间 我不是很理解什么意思,网上看到的很多都是错的。
流量控制 匀速排队模式 · alibaba/Sentinel Wiki · GitHub
官网上是这么说的
固定的间隔时间让请求通过。当请求到来的时候,如果当前请求距离上个通过的请求通过的时间间隔不小于预设值,则让当前请求通过;否则,计算当前请求的预期通过时间,如果该请求的预期通过时间小于规则预设的 timeout 时间,则该请求会等待直到预设时间到来通过(排队等待处理);若预期的通过时间超出最大排队时长,则直接拒接这个请求。
不知道有没有小伙伴不吝赐教下!
PS:都看到这里了,点个赞吧,彦祖!
更多推荐
所有评论(0)