目录
一、Sentinel 限流规则
1.1、簇点链路
1.2、流控模式
1.2.1、直接流控模式
1.2.2、关联流控模式
a)在 OrderController 中新建两个端点.
b)在 Sentinel 控制台中对订单查询端点进行流控
c)使用 JMeter 进行测试
d)分析结果
1.2.3、链路流控模式
a)在 OrderService 中添加 queryGoods 方法(不用实现业务).
b)在 OrderController 中创建两个端点,分别是 /order/query 和 /order/save
c)给 queryGoods 设置限流规则
d)使用 JMeter 进行测试
1.3、流控效果
1.3.1、快速失败
1.3.2、warm up
a)设置限流规则
b)使用 JMeter 进行测试
c)分析结果
1.3.3、排队等待
a)配置流控规则
b)使用 JMeter 进行测试
c)分析结果
1.3.4、热点参数限流
a)给热点参数限流对象加上 @SentinelResource 注解
c)使用 JMeter 进行测试
d)分析测试结果
一、Sentinel 限流规则
1.1、簇点链路
在 Sentinel 控制台中有这样一个选项.
簇点链路,就是项目内的调用链路.
在 SpringMVC 中,请求先在 Controller 中路由到对应的方法,然后在方法中调用 Sevice 中的方法,最后调用对应的 Mapper 接口,这个过程就是一个调用链路.
链路中被监控的每一个接口就是一个资源(RequestMapping 就是资源路由),默认情况下,会监控 SpringMVC 的每一个端点(也就是 Controller 中的每一个资源),因此 SpringMVC 中每一个端点就是调用链中的一个资源.
流量、熔断等都是针对簇点链路中的资源来设置的.
1.2、流控模式
1.2.1、直接流控模式
在访问 /order/{orderId} 后,打开 Sentinle 控制台,选择 “簇点链路” 就可以看到下图.
点击资源 /order/{orderId} 后面的流控按钮,就会弹出表单,之后就可以添加限流规则.
这里我们先来看一下,直接流控模式(打开高级选项后,即可看到默认选中)
- 针对来源:默认为 default,也就是对所有的请求有效,这里一般不做修改.
- 阈值类型:这里就是用 qps 即可,也就是每秒处理请求的最大个数.
- 单机阈值:设置每秒处理请求的最大个数.
- 流量模式:这里有三种,当前我们先看第一种,就是统计当前资源的请求,如果超过单机阈值,就进行限流.
- 流控效果:快速失败是默认,是指到达阈值后,新请求会立刻被拒绝并抛出 FlowException 异常.
这里设置单机阈值为 5.
然后通过 JMeter 测试工具实现每秒中发送 10 个请求,总共持续 2s.
设置 Http 请求
启动脚本,观察运行结果,可以看到差不多是每 5 条成功,5条失败.
在 Sentinel 中就可以观察到QPS 的通过和拒绝情况.
1.2.2、关联流控模式
关联模式:用来统计与当前资源相关的另一个资源,触发阈值时,对当前资源进行限流.
举个例子,你在淘宝上买东西,完成支付以后会进行修改订单状态的业务,与此同时,你还要查看订单,但是 查询 和 修改 都会争抢数据库的锁,产生竞争. 根据业务需求是,优先进行更新订单业务,之后进行用户查询业务,因此当修改订单业务触发阈值时,就需要对查询订单业务进行限流.
可以看出,关联流控模式的适用场景满足以下条件:
- 两个资源有竞争关系.
- 一个优先级高,一个优先级低.
这里用一个案例来演示:在 OrderController 中创建两个端点,/order/query 和 /order/update ,不用实现业务,接着配置流控规则,当 /order/update 资源被访问的 QPS 超过 5 时,对 /order/query 请求限流.
具体实现步骤如下:
a)在 OrderController 中新建两个端点.
创建 /order/query 和 /order/update 端点.
@RequestMapping("/query")
public String queryOrder() {
return "订单查询成功!";
}
@RequestMapping("update")
public String updateOrder() {
return "订单修改成功!";
}
b)在 Sentinel 控制台中对订单查询端点进行流控
单机阈值设置为 5,流控模式选择 “关联”,关联资源就是 /order/update.
也就是说,当 /order/update 达到阈值以后,再发送 /order/query 请求就会抛出异常.
c)使用 JMeter 进行测试
设置每秒发送 10 个请求,总共发 1000 个请求.
这里对 /order/update 发送请求即可.
d)分析结果
JMeter 运行期间,手动发送一个 /order/query 请求,会发现请求失败.
这是因为此时 /order/update 已经超出阈值,此时再发送 /order/query 请求,那么两个请求的总数加起来肯定也是超过阈值的,因此由于设定了 “流控效果” 为快速失败,所以这里抛出异常.
1.2.3、链路流控模式
链路模式:只针对从指定链路访问到当前指定资源的请求做统计,如果超过阈值,则对当前链路进行限流.
例如现在有两条请求链路:
- /test1 -> /tools
- /test2 -> /tools
如果只希望统计从 /test2 进入 /tools 请求,那么一旦超过阈值(假设阈值为 5),只对此线路进行限流,则可以进行如下配置:
这里用一个案例来演示: 现有 查询订单 和 创建订单 业务,两者都需要进行查询商品业务. 需求是指针对 查询订单 -> 查询商品 的请求进行统计并设置流控(阈值为 2).
具体实现步骤如下:
a)在 OrderService 中添加 queryGoods 方法(不用实现业务).
用来表示两个 查询订单 和 创建订单 两个业务都要访问的 查询商品业务.
@SentinelResource("goods") //设置资源名称
public void queryGoods() {
//使用 err 是为了高亮显示,方便观察日志信息
System.err.println("查询订单成功!");
}
注意!!!
1. Sentinel 默认值只标记 Controller 中方法为资源,如果想要标记其他方法,需要使用 @SentinelResource 注解来标识资源名.
2. 另外!Sentinel 默认只对 Controller 中的方法做 context 整合,导致链路模式的流控失效,需要 application.yml 中添加如下配置:
spring:
cloud:
sentinel:
web-context-unify: false # 关闭context整合
触发两个端点,就可以看到在 “簇点链路” 中 goods 为两个端点资源的子资源,如下
b)在 OrderController 中创建两个端点,分别是 /order/query 和 /order/save
两个端点中都需要调用 Order Service 中的 queryGoods 方法.
@RequestMapping("/query")
public String queryOrder() {
orderService.queryGoods();
return "订单查询成功!";
}
@RequestMapping("/save")
public String saveOrder() {
orderService.queryGoods();
return "保存订单成功!";
}
c)给 queryGoods 设置限流规则
针对从 /order/query -> queryGoods 此链路进行限流,阈值为 2.
d)使用 JMeter 进行测试
使用 JMeter 对两个端点都进行 每秒发送 4 个请求.
可以看到在 /order/save -> goods 这个链路中请求都成功了.
而 /order/query -> goods 这条链路中,被流控模式限制.
在控制台上也可以看到 goods 的 qps 拒绝情况(每 8 个 qps 中有 2 个被拒绝,拒绝的就是 /order/query 这条链路超过阈值的请求).
1.3、流控效果
1.3.1、快速失败
快速失败:达到阈值以后,新的请求会立即拒绝并抛出 FlowException 异常,是默认的处理方式
这种方式在演示 流控模式 中都用是这个效果,这里就不再赘述了.
1.3.2、warm up
warm up:预热模式,对超出阈值的请求同样是拒绝并抛出异常. 但是这种模式的阈值会动态变化,从一个比较小的值逐渐增加到设置的最大阈值(这里的预热时间是需要进行设置的).
请求阈值的初始值是 设置的最大阈值 / coldFactor ,而 coldFactor 默认值是 3.
例如我设置 qps 的最大阈值为 10,预热时间是 5秒,那么初始的阈值就是 10 / 3,取整后就是 3,之后再 5秒 以后逐渐增长到 10.
这里我通过一个案例来演示:给 /order/{orderId} 这个资源设置限流,最大 qps 为 10,使用 warm up 效果,预热时常为 5 秒.
具体步骤如下:
a)设置限流规则
b)使用 JMeter 进行测试
c)分析结果
在控制台中可以看到,刚开始的 qps 只通过 3(初始阈值计算后得到的)符合预期,之后 5 秒中内,qps 通过数目逐渐上升,直到 qps 通过数目 = 10 以后稳定下来.
1.3.3、排队等待
排队等待这种方式,当请求超过 qps 阈值之后,不会直接抛出异常,而是让多出来的请求先进入到一个队列中进行排队,然后按照阈值允许的时间间隔依次执行,如果队列中所有的请求处理时间加起来刚好等于等待时间,那么,此时新来的请求就会被拒绝.
例如,设置 qps = 5,意味着每 200ms 处理一个队列中的请求. 如果设置 超时时间 为 2000ms,那么意味着队列中如果有 10 个请求,就会把时间占满,此时如果再来新的请求,就会被拒绝.
这里用一个案例来演示:给 /order/{orderId} 这个资源设置限流,最大 qps 为 10,利用排队的流控效果,超时时间设置为 5s.
a)配置流控规则
b)使用 JMeter 进行测试
c)分析结果
该开始的时候,都处理成功了是因为新加入的请求都会先进入队列,并且队头的请求也被处理掉了。
而后来的由于请求来的速度大于队列处理的速度,因此队列终有一日会占满超时时间,因此出现了拒绝 qps 的情况.
最后请求请求发完了,队列不停的再处理请求,就不会超过超时时间,因此最后的 qps 全部为通过.
1.3.4、热点参数限流
之前的限流是统计访问某个资源的所有请求,判断是否超过 qps 阈值,而热点参数限流是统计 参数值 相同的请求,是否超过 qps 阈值.
例如,对 hot 这个资源的 0 号参数(第一个参数)做统计,每 1 秒相同参数的请求数不能超过 5,如下图.
另外,在热点参数限流的高级选项中,还可以对部分参数进行外额限制
参数类型:参数索引指向的参数是什么数据类型(只支持 Java 数据类型).
参数值:传入的参数值.
限流阈值:窗口时长内,qps 的最大阈值.
例如,如果参数值是 100,则每秒允许的 qps 为 10,如下图.
这里我用一个案例来演示:给 /order/{orderId} 这个资源添加热点参数限流,规则如下:
- 默认的热点参数规则是每 1 秒请求量不超过 2.
- 给 102 这个参数设置例外:每 1 秒请求量不超过 4.
- 给 103 这个参数设置例外:每 1 秒请求量不超过 10.
具体实现步骤如下:
a)给热点参数限流对象加上 @SentinelResource 注解
注意:热点参数限流对默认的 SpringMVC资源无效,因此需要加上 @SentinelResource 指定资源并命名.
@SentinelResource("hot")
@GetMapping("{orderId}")
public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
// 根据id查询订单并返回
return orderService.queryOrderById(orderId);
}
b)配置限流规则
c)使用 JMeter 进行测试
发送路径有三个,如下:
d)分析测试结果
可以看到 101 这个请求,按照默认的限流规则, qps = 2 ,如下.
102 这个请求,按照高级设置,例外配置 qps = 4,如下.
103 这个请求,按照高级设置,例外配置 qps = 10. 因为每秒请求数为 5 个,因此请求全部通过.
在 hot 资源监控中也可以看到,每次 11 ,拒绝 4.
是因为通过的只有 101 请求默认规则的 2 个,加上 102 请求例外设置的 4 个,再加上 103 请求例外设置的 5 个,总共加起来成功就是 11 个.