目录
流控规则简介
基本介绍
是否集群
单机均摊:假设当前服务,集群三台机器,均摊阈值100,表示三台机器各自都能承受100的阈值
总体阈值:假设当前服务,集群三台机器,集群阈值100,表示三台机器总共能承受100的阈值,各自承受多少,由负载均衡决定了
流控模式
一、直接(默认)
接口达到限流条件时,直接限流。
一秒内访问次数超过一,直接快速报错
思考???
这个默认的报错,我们应该能自定义吧。
流控效果:QPS与线程数的区别
QPS
:表示如果1秒内的请求数超过了,设置的阈值,限流,直接不让进。这个是御敌于国门之外
线程数:假设阈值是1,表示请求全部接受,但是只有一条线程处理,处理不了的报错。这个是放进来,关门打狗。
测试:
接口改一下:假设业务逻辑执行900毫秒
@GetMapping("/testA")
public String testA() {
try {
TimeUnit.MILLISECONDS.sleep(900);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "------testA";
}
访问:http://localhost:8401/testA
执行完一次,请求在,刷新一次,是能正常访问的。
但是上一次请求还没执行完,还在转圈圈的时候,就继续访问:
线程就只有一条来处理请求,请求一下来太多,搞不定,直接报错。
二、关联
当关联的资源达到阈值时,就限流自己,当与A关联的资源B达到阈值后,就限流A自己。
比如:支付接口达到阈值,就限流下订单接口。
例如:
设置一个流控规则/testA
,关联的是/testB
,只要/testB
每秒的请求数超过1,就限流/testA
接口。
并发访问/testB
,必然触发阈值
这期间,访问/testA
接口:
并发访问/testB
之后:再访问接口testA
,又不限流了,无论多快的访问都没事。
三、链路
只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)。
A->B->C
链路上指定入口资源/A
,只有从/A->/B->/C
.才有效,从/B
进来的资源不算或者从别的链路进来的也不算
在sentinel_web_servlet_context
下有几个请求资源地址:
我的是:
/testA
/testB
给接口/testA
添加流控规则,链路为sentinel_web_servlet_context->/testA
然后再发送请求至"host:port/testA"时,如果1秒内请求次数超过1次,就会自动触发限流。
此外,通过其他微服务模块请求testA时,如果1秒内请求次数超过1次,同样会触发限流。
流控模式为“链路模式”下的配置就此完成。
流控效果
一、直接->快速失败(默认的流控处理)
直接失败,抛出异常:Blocked by Sentinel (flow limiting)
源码:com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController
二、预热Warm Up
Warm Up
方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。
通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。
公式:阈值除以coldFactor
(默认值为3),经过预热时长后才会达到阈值。coldFactor
:冷加载因子
默认coldFactor
为3,即请求QPS
从threshold/3
开始,经预热时长逐渐升至设定的QPS
阈值。
例如:/testA
接口阈值为10,希望的效果是最终能承受1秒10个请求,但是得预热一段时间5秒,预热时间的阈值为10/3=3
,QPS
为3,过了5秒后,慢慢的阈值从3升到10。
源码:com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController
可以看到冷加载因子默认是3
测试:http://localhost:8401/testA
一直访问这个接口,前5秒会出现
但是后5秒无论你怎么刷新,都不会出现了,除非你手速你达到1秒刷新超过10次的速度。
应用场景:
三、排队等待
匀速排队,让请求以均匀的速度通过,阈值类型必须设为QPS
,否则无效。
想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。
例如:
意思就是:/testA
每秒1次请求,超过的话就排队等待,等待的超时时间为20000毫秒。
测试:
@GetMapping("/testA")
public String testA() {
log.info(Thread.currentThread().getName()+"\t"+"...testB");
return "------testA";
}
并发访问10个请求,每个请求的时间间隔300毫秒。
把阈值改为2,每秒处理2个请求