转载声明 : 该文章出处为 扛麻袋的少年
本文目录:
-
- 写在开头
- 1.流控规则
-
- 1.1 阈值类型:QPS
- 1.2 阈值类型:线程数
- 1.3 流控模式:直接
- 1.4 流控模式:关联
- 1.5 流控模式:链路
- 1.6 流控效果:快速失败
- 1.7 流控效果:Warm Up
- 1.8 流控效果:排队等待
- 2.降级规则
-
- 2.1 RT
- 2.2 异常比例
- 2.3 异常数
- 3.热点规则
-
- 3.1 何为热点
- 3.2 何为热点限流
- 3.3 热点规则
-
- Ⅰ.基本配置
- Ⅱ.参数例外项配置
- 4.系统规则
-
- 1.系统规则支持以下模式
- 2. 入口QPS配置
写在开头
接上一篇文章:Spring Cloud Alibaba Sentinel 介绍、简单使用。学习了Sentinel 的基本使用,接下来我们就对 Sentine 中的
那些规则
进行一一介绍,本文重点讲以下4个。

1.流控规则
流控规则,即:流量控制规则。可自行参考官网介绍:GitHub 流量控制。具体配置有
资源名
、
针对来源
、
阈值类型
、
是否集群
、
流控模式
、
单机阈值
、
流控效果
这几项,它们配合进行使用。每一项具体代表的什么含义,且听我娓娓道来。
资源名
:唯一路径,默认为请求路径(也可以是后续介绍的 @SentinelResource 注解的 value 属性值)
针对来源
:Sentinel 可以针对调用者进行限流,填写微服务名。默认为 default(不区分来源)
:本文为单机测试,是否集群不选
是否集群
1.1 阈值类型:QPS
QPS(每秒钟的请求数量):当调用该 API 的
QPS
达到阈值的时候,进行限流。
配置:
配置说明:
/testA 服务,每秒只允许调用 1 次,超出阈值后,流控效果为:
直接 → 快速失败
(流控效果如果不选,默认为
直接 → 快速失败
)。
资源名称 | 阈值类型 | 单机阈值 | 流控模式 | 流控效果 |
---|---|---|---|---|
/testA | | 1 | 直接 | 快速失败 |
业务代码:
@RestController
public class FlowLimitController {
@GetMapping("/testA")
public String testA() throws InterruptedException {
return "-----testA";
}
}
测试:
开始,每秒调用 /testA 服务 1次,服务正常。后续狂点刷新调用服务,显然超过 Sentinel 设定的 QPS = 1,就会进行流量控制:
快速失败
(流控 Sentinel 默认提示:
Blocked by Sentinel(flow limiting)
)
1.2 阈值类型:线程数
线程数:当调用该 API 的
线程数
达到阈值的时候,进行限流。
配置:
配置说明:
/testA 服务,单个线程只允许调用 2 次,超出阈值后,流控效果为:
直接 → 快速失败
。
资源名称 | 阈值类型 | 单机阈值 | 流控模式 | 流控效果 |
---|---|---|---|---|
/testA | | | 直接 | 快速失败 |
业务代码:
/**
* 使/testA休眠6s
*/
@RestController
public class FlowLimitController {
@GetMapping("/testA")
public String testA() throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(6000);
return "-----testA";
}
}
测试:
开始,调用 /testA 服务 2 次,服务正常,但是 sleep 导致服务没有返回。当第 3 次调用时,显然超过 Sentinel 设定的 线程数 = 2,就会进行流量控制:
快速失败
(本次以 Firefox 进行测试,Chrome 是多线程执行??总是出不来效果,和浏览器设计有关系吧,此处就不过多考虑)
1.3 流控模式:直接
流控模式:直接,已经介绍,字面理解即可。没啥可说的。
这些选项都是配合使用的,理解意思即可
1.4 流控模式:关联
关联:当关联的资源达到阈值时,就限流自己。
当与 A 资源关联的 B 资源达到阈值时,就限流自己(A)
,即:B惹事,A挂了
应用场景:
双十一,
支付接口
和
下单接口
关联。当支付接口达到阈值,就限流下单接口
配置:
配置说明:
/testA
服务关联
/testB
服务,1s 调用 1次,服务正常。当狂点刷新调用
/testB
服务,超出阈值 QPS = 1 后,此时 /testA 被限流了,这就是
B惹事,A挂了
。
资源名称 | 阈值类型 | 单机阈值 | 流控模式 | 关联资源 | 流控效果 |
---|---|---|---|---|---|
/testA | | | 关联 | | 快速失败 |
业务代码:
/**
* 使/testA休眠6s
*/
@RestController
public class FlowLimitController {
@GetMapping("/testA")
public String testA(){
return "-----testA";
}
@GetMapping("/testB")
public String testB(){
return "-----testB";
}
}
测试:
开始,/testA 和 /testB 1次/s 可以正常调用,突然大批量访问打到 /testB 请求。由于关联的 /testB 请求超过设定的阈值 QPS = 1,导致 /testA 请求被限流了。
1.5 流控模式:链路
链路:当链路中的资源达到阈值时,就会对使用到该资源的链路进行流控。
当 A01 资源达到设定阈值时,所有调用该服务的链路,都会被限流
,即:
A01 挂了,用到我的链路都得挂
此处会用到
@SentinelResource
注解 value 属性值
作为资源名
。此处只是使用一下。该注解的详细使用,请跳转链接:@SentinelResource 介绍
模拟两条请求链路:
- A链路:
A → A01 → A04 → A05
- B链路:
B → A01 → A02 → A03
Spring Cloud Alibaba Sentinel 流控、降级、热点、系统规则详解
配置:
配置说明:
对
testA01
服务进行
链路
流控,该服务关联有 A 和 B 两条链路。当 A 链路1s 调用 1次,服务正常。当该链路调用
超出阈值 QPS = 1 后,此时A链路都会被限流,同时因为B链路也调用 testA01,所以B链路也会同时被限流调用
。
资源名称 | 针对来源 | 阈值类型 | 单机阈值 | 流控模式 | 入口资源 | 流控效果 |
---|---|---|---|---|---|---|
| default | | | 链路 | | 快速失败 |
业务代码:
/**
* Controller代码
*/
@RestController
@Slf4j
public class FlowLimitController {
@Resource(name = "commonService")
public CommonService commonService;
@GetMapping("/testA")
@SentinelResource("testA")
public String testA(){
commonService.testA01();
return "-----testA";
}
@GetMapping("/testB")
@SentinelResource("testB")
public String testB(){
commonService.testA01();
return "-----testB";
}
}
/**
* Service代码
*/
@Service("commonService")
@Slf4j
public class CommonService {
@SentinelResource(value = "testA01")
public void testA01() {
testA02();
testA04();
log.info("-----testA01");
}
@SentinelResource(value = "testA02")
public void testA02() {
testA03();
log.info("-----testA02");
}
@SentinelResource(value = "testA03")
public void testA03() {
log.info("-----testA03");
}
@SentinelResource(value = "testA04")
public void testA04() {
testA05();
log.info("-----testA04");
}
@SentinelResource(value = "testA05")
public void testA05() {
log.info("-----testA05");
}
}
测试:
开始,对
/testA 请求
1次/s 可以正常调用,当
/testA 请求
QPS > 1 后,满足设定的
testA01链路流控
规则 ,所以
/testA 请求
会被限流。同时
/testB 请求
也会被限流。 (即:testA01 QPS=1,1s 只允许调用1次,超出之后,调用 testA01 的所有链路将都会被限流)
手速原因,此处使用 postman 1s 发送 10个请求(/testA 和 /testB 各10个),测试图如下所示:
1.6 流控效果:快速失败
流控效果:快速失败,已经介绍,字面理解即可。没啥可说的。
这些选项都是配合使用的,理解意思即可
1.7 流控效果:Warm Up
Warm Up:某个服务,日常访问量很少,基本为 0,突然1s访问量 10w,这种极端情况,会直接将服务击垮。所以通过配置
流控效果:Warm Up
,允许系统慢慢呼呼的进行预热,经预热时长逐渐升至设定的QPS阈值。
公式计算:
公式:阈值/coldFactor(默认值为3)
应用场景:
秒杀系统。秒杀系统在开启的瞬间,会有很多的流量上来,很有可能将系统打死。预热方式就是为了保护系统,可以慢慢的将流量放进来,最终将阈值增长到指定的数值
配置:
配置说明:
/testA
服务,设置 QPS 单机阈值为 10,采用 Warm Up 预热的方式,预热时长为 5s。根据计算公式
10 / 3 = 3
,前 5s 的阈值为 3,预热 5s 后阈值增长到 10。
资源名称 | 阈值类型 | 单机阈值 | 流控模式 | 流控效果 | 预热时长 |
---|---|---|---|---|---|
/testA | | | 直接 | | |
业务代码:
/**
* 使/testA休眠6s
*/
@RestController
public class FlowLimitController {
@GetMapping("/testA")
public String testA(){
return "-----testA";
}
@GetMapping("/testB")
public String testB(){
return "-----testB";
}
}
测试:
开始调用 /testA 服务,狂点刷新访问打到 /testA 请求。配置
Warm Up
流控效果,在前 5s 内,通过公式计算阈值为
10/3 = 3
,访问超过 3 次便会被限流;5s 后,阈值增长到 10,此时访问超过 3 次也不会被限流,这就是 Warm Up 预热效果。
1.8 流控效果:排队等待
排队等待:让请求以均匀的速度通过,对应的是漏桶算法。这种方式主要用于处理间隔性突发的流量,例如消息队列。
应用场景:
在某一秒有大亮的请求到来,而接下来的几秒则处于空闲状态。我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。
配置:
配置说明:
/testA
服务,设置 QPS 单机阈值为 2,每秒只接收 2 个请求。设置超时时间 5s。采用漏斗算法,让后台匀速的处理请求,而不是直接拒绝更多的请求。超时的请求则被抛弃,返回错误信息。
资源名称 | 阈值类型 | 单机阈值 | 流控模式 | 流控效果 | 预热时长 |
---|---|---|---|---|---|
/testA | | | 直接 | | |
业务代码:
/**
* 使/testA休眠6s
*/
@RestController
public class FlowLimitController {
@GetMapping("/testA")
public String testA(){
return "-----testA";
}
}
测试:
手速不够,此处就使用 postman 一次发送 100 个请求,设置 QPS = 2,其他请求将会排队等待。每秒只接收 2 个请求。我们会看到动态监控,
通过QPS为 2,拒绝QPS 为 0,平均响应时间为 480ms,我们设置超时时间为 5000ms,所以拒绝QPS 为 0,如果超时时间为 200ms,拒绝 QPS 就会上升。100个请求发送完成,随之通过QPS降下来了。
postman 一次如何发送多个请求,参考:postman 点击一次连续发送多个请求
2.降级规则
降级规则。可自行参考官网介绍:GitHub 熔断降级。降级策略有
RT
、
异常比例
、
异常数
三种,每一项具体代表的什么含义,继续听我娓娓道来。
资源名
:唯一路径,默认为请求路径(也可以是后续介绍的 @SentinelResource 注解的 value 属性值)
2.1 RT
RT:即
平均响应时间(DEGRADE_GRADE_RT)
。官网介绍太笼统,此处不Copy 了,要看官网介绍来这里:RT 平均响应时间介绍
注意 Sentinel 默认统计的 RT 上限是 4900 ms,超出此阈值的都会算作 4900 ms,若需要变更此上限可以通过启动配置项 -Dcsp.sentinel.statistic.max.rt=xxx 来配置。
图示:
配置:
配置说明:
/testA
服务,设置 降级策略为
RT
,RT(平均响应时间)为
200ms
,时间窗口为
5s
。发送请求平均响应时间在 200ms 内,正常访问不会被熔断降级。当平均响应时间 > 200ms,便会被熔断降级。
时间窗口5s内断路器处于打开状态,无法提供服务,时间窗口结束,服务恢复正常访问。就是服务会被熔断5s的意思
(切记是平均响应时间)
资源名称 | 降级策略 | RT(平均响应时间) | 时间窗口 |
---|---|---|---|
/testA | | | |
业务代码:
/**
* 使/testA休眠300ms
*/
@RestController
public class FlowLimitController {
@GetMapping("/testA")
public String testA() throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(300);
return "-----testA";
}
}
测试:
RT降级规则,需要同时满足:
1.QPS>=5
&&
2.平均响应时长> 200
两个条件。手动发送请求操作看的明显,此时 1秒钟发送 >5 个请求,由于每个请求都 sleep 300ms,请求最终平均响应时间为 300+ ms,肯定 > 200ms。
满足上述两个条件,执行 RT 降级规则,开始熔断后,时间窗口期5s内,断路器处于打开状态,此时为熔断阶段,时间窗口结束,断路器关闭,关闭服务熔断,服务可以正常访问。
如图所示:
2.2 异常比例
异常比例:
QPS >= 5
&&
异常比例超过设定的阈值
,便会发生服务降级 。
异常比例为 0.0~1.0 范围内值。
时间窗口就是断路器开启时间长短(降级时间)
。要看官网介绍来这里:异常比例介绍
图示:
配置:
配置说明:
/testA
服务,设置 降级策略为
异常比例
,异常比例设为
0.5
,时间窗口为
5s
。即:1s 发送6个请求,异常比例超过 50%,就会被熔断,断路器打开5s,5s后自动关闭,继续提供服务。
资源名称 | 降级策略 | 异常比例(0.0-1.0) | 时间窗口 |
---|---|---|---|
/testA | | | |
业务代码:
/**
* 自己造一个 by zero 异常
*/
@RestController
public class FlowLimitController {
@GetMapping("/testA")
public String testA(){
int i = 10/0;
return "-----testA";
}
}
测试:
我们配置的异常比例降级规则,需要同时满足:
1.QPS>=5
&&
2.异常比例> 50%
两个条件。手动发送请求操作看的明显,此时 1秒钟发送 >5 个请求,因为每个请求都是异常,异常比例 100%。
如果1s发送6次请求,前3次报错,因为第4次访问后,异常比例 > 50%,第4次便会被熔断,报
Blocked by Sentinel(flow limiting)
。5s后继续提供服务哦。测试结果如图所示:
2.3 异常数
异常数:指的是资源
近1分钟
的异常数目,超过阈值之后会进行熔断。
重点注意:异常数,统计时间窗口是分钟级别,若 timeWindow 小于 60s,则结束熔断状态后仍可能再次进入熔断状态。推荐
时间窗口一定要>=60s
官网介绍来这里看:异常数介绍
图示:
配置:
配置说明:
/testA
服务,设置 降级策略为
异常数
,异常数设为
5
,时间窗口为
60s
。即:调用服务,当异常数超过5个时,开启断路器,执行熔断操作。60s 后,断路器关闭,服务恢复正常,如下图:
资源名称 | 降级策略 | 异常数 | 时间窗口 |
---|---|---|---|
/testA | | | |
业务代码:
/**
* 自己造一个 by zero 异常
*/
@RestController
public class FlowLimitController {
@GetMapping("/testA")
public String testA(){
int i = 10/0;
return "-----testA";
}
}
测试:
执行 /testA 服务请求,因为每个请求都是异常,前5次调用正常返回,只是报异常到前台;第6次服务调用时,便会被降级熔断。报
Blocked by Sentinel(flow limiting)
。60s后继续提供服务哦。测试结果如图所示:
3.热点规则
3.1 何为热点
(本段内容摘自:Github 热点规则官方介绍)
何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:
商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。
热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。热点参数限流支持集群模式。(详细介绍,参考:Github 热点规则官方介绍)
3.2 何为热点限流
一句话解释:根据 url 传递进来的参数进行限流。带这个参数就限流,不带就不限流。
3.3 热点规则
热点规则。可自行参考官网介绍:GitHub 热点参数限流,共有
资源名
、
限流模式(只支持QPS模式)
、
参数索引
、
单机阈值
、
统计窗口时长
、
是否集群
六种参数;高级选项还有额外一些参数,在用到时介绍。每一项具体代表的什么含义,来继续听我絮絮叨叨吧。
此处会用到
@SentinelResource
注解 value 属性值
作为资源名
。此处只是使用一下。该注解的详细使用,请跳转链接:@SentinelResource 介绍
:唯一路径,默认为请求路径。此处必须是 @SentinelResource 注解的 value 属性值,配置@GetMapping 的请求路径无效)
资源名
:参数索引(从0开始,0表示第一个参数、1表示第二个参数)
参数索引
Ⅰ.基本配置
[email protected] 注解说明
@SentinelResource 注解,与 @HystrixCommand 类似,也是用来定义服务降级
兜底方法
的注解。该注解有很多属性可以配置。在下一篇会系统介绍:@SentinelResource 介绍
2.业务代码:
@RestController
public class FlowLimitController {
@GetMapping("/testC")
@SentinelResource(value = "testC") //此处value值,一般为@GetMapping属性值去掉斜杠
public String testC(@RequestParam(value = "id",required = false) Integer id,
@RequestParam(value = "name",required = false) String name){
return "-----testC";
}
}
3.配置:
4.配置说明:
对
/testC
服务,配置热点key限流。当 1.参数 name 存在 2.一秒内调用
/testC
服务 > 5次,满足限流规则。服务将被熔断。断路器打开,5s 后服务恢复正常
资源名称 | 参数索引 | 单机阈值 | 统计窗口时长 |
---|---|---|---|
(不能是请求路径,否则无效) | | | |
5.测试:
调用 URL:
http://localhost:8401/testC?id=1&name=James
,1.参数 name 存在 2.一秒内调用
/testC
服务 > 5次,满足限流规则。服务将被熔断。断路器打开,5s 后服务恢复正常。如下图:
6.友好处理
被限流后,直接报错
java.lang.refletc.UndeclaredThrowableException
。异常显示到前台用户界面,显然不是不友好。
此处也是需要用到 @SentinelResource 的 blockHandler 属性,它是 Sentinel控制台违规的兜底方法配置(还会j介绍一个 fallback属性,它是@GetMapping请求Java 方法执行出现异常的兜底方法配置,要分清楚)
兜底方法配置,在下一篇介绍:@SentinelResource 介绍
Ⅱ.参数例外项配置
1.需求:
当 name 参数值为
Wade
时,限流阈值变更为 100。此时就需要对
参数例外项
进行配置了。
参数类型
支持:
int
、
double
、
String
、
long
、
float
、
char
、
byte
7种类型,
参数值
指 name 参数的值,
限流阈值
指该参数值允许的阈值。
2.配置:
3.测试:
调用 URL:
http://localhost:8401/testC?id=1&name=Wade
,虽然 name 参数存在,但是配置了 Wade 限流阈值为 100。我手速没那么快,哈哈,所以不会进入熔断。如下图所示:
4.系统规则
系统保护规则是从应用级别的入口流量进行控制
,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。
Sentinel 系统自适应限流从整体维度对应用入口流量进行控制
,结合应用的 Load、CPU 使用率、总体平均 RT、入口 QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
1.系统规则支持以下模式
- Load 自适应(仅对 Linux/Unix-like 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps * minRt 估算得出。设定参考值一般是 CPU cores * 2.5。
- CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。
- 平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
- 并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
- 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
此处内容,
CPU 使用率
、
总平均 RT
、
并发线程数
等也不好演示,理解意思知道有这块用于全局应用入口流量控制就可以了,详细介绍还是参考官网来吧:热点参数限流
2. 入口QPS配置
入口QPS,实用性还是比较危险的。 如果 sentinel 密码被修改,将你的整个系统
入口QPS
配置很小,那么整个系统就瘫痪了。
但是 入口QPS 有总控的功能。最终选择是否使用,还是视情况而定吧
配置:
配置说明:
整个系统,每个请求 QPS = 1 正常访问,当该请求 QPS >1 就会被限流。
测试:
本文代码不提供,将文中业务代码配合如下代码使用即可。下载地址:Spring Cloud Alibaba Sentinel 简单使用 (提取码:nfmb)
下一篇:来聊聊@SentinelResource的用法