流控规则基本概念

  • 资源名:唯一名称,默认请求路径
  • 针对来源: Sentinel可以针对调用者进行限流,填写微服务名,默认 default(不区分来源)
  • 阈值类型单机阈值:
    • QPS(每秒钟的请求数量):当调用该api的QPS达到阈值的时候,进行限流
    • 线程数:当调用该api的线程数达到阈值的时候,进行限流
  • 是否集群:不需要集群
  • 流控模式:
    1. 直接:api达到限流条件时,直接限流
    2. 关联:当关联的资源达到阈值时,就限流自己
    3. 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)【api级别的针对来源】
  • 流控效果:
    1. 快速失败:直接失败,抛异常
    2. Warm Up:根据 codeFactor(冷加载因子,默认3)的值,从阈值 / codeFactor,经过预热时长,オ达到设置的QPS阈值
    3. 排队等待:匀速排队,让请求以匀速的速度通过,阈值类型必须设置为QPS,否则无效

流控模式

QPS直接失败

直接->快速失败:系统默认

配置及说明:

1610803441889.png

表示1秒内查询1次就ok,操作1次就直接—快速失败,报默认错误

1610803441934.png

结果:如果访问http://localhost:8401/testA,在1s内超过1次就报如下的错误

1610803441966.png

思考

直接调用默认报错信息,技术方面OK

类似有一个fallback的兜底方法?

线程数直接报错

1610803442001.png

QPS和线程数控制的区别

QPS:设定QPS后,如果1s内访问量操作所设定的值,用户还没有进入到线程处理中就被挡在大门外了

线程数:设置单机阈值后,访问只能由一个线程处理,如果A接口中的线程没有处理完当前业务,又有用户访问A接口,则会报错

1610803442034.png

控制层代码

  1. @RestController
  2. public class FlowLimitController {
  3. @GetMapping("/testA")
  4. public String testA() throws InterruptedException {
  5. System.out.println(Thread.currentThread().getName());
  6. // 暂停多少s
  7. TimeUnit.SECONDS.sleep(2);
  8. return Thread.currentThread().getName() + "\t------------testA";
  9. }
  10. @GetMapping("/testB")
  11. public String testB() {
  12. return "------------testB";
  13. }
  14. }

测试

线程数,单机阈值:指的是服务器运行开多少个线程访问controller层

访问:http://localhost:8401/testA,在2s内再访问 http://localhost:8401/testA,就会直接报错

这里有一个问题:当你使用浏览器打开两个页面访问同一个url的时候,出现如下情况,你会先,当在2s内访问第二次的时候一直在转圈,而不是直接给予拒绝响应

1610803442080.gif

关于微软Edge浏览器同一个url访问问题

当你使用浏览器打开两个页面访问同一个url的时候,浏览器是这样做的

  • 首先第一次访问url
  • 这时候还没等到第一次访问返回结果,我就开始新打开一个标签进行第二次访问同一个url
  • 第2次访问的url会等第一次访问返回结果后才会向服务器发送第二次请求

那我们该如何处理这种情况呢?想要第二次访问不要等到第一次访问返回结果才去进行访问服务器

很简单,只要你在第二次访问的页面上按F12,打开控制台即可

1610803442142.gif

关于谷歌浏览器同一个url访问问题

不知道解决办法

关于火狐浏览器同一个url访问问题

火狐浏览器没有出现上述情况,可以正常使用,推荐以后开发中使用火狐浏览器

使用火狐浏览器接着测试

1610803442198.gif

关联

是什么

当关联的资源达到阈值时,就限流自己

当与A关联的资源B达到阈值后,就限流自己

B惹事,A挂了

配置A

当关联资源/testB的qps阈值超过1时,就限流/testA的Rest访问地址,当关联资源到阈偵后限制配置好的资源名

1610803442236.png

postman模拟并发密集访问testB

访问testB成功

1610803442269.png

postman里新建多线程集合组

先保存url

1610803442309.png

创建线程集合组

1610803442346.png

1610803442383.png

大批量线程高并发访问B,导致A失效了

1610803442418.png

这时候使用浏览器访问A,A访问失败

1610803442444.png

默认的流控处理

直接失败,抛出异常

Blocked by Sentinel (flow limiting)

源码

com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController

预热

说明

公式:阈值除以coldFactor(默认值为3),经过预热时长后才会达到阈值

官网

1610803442507.png

1610803442552.png

源码

com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController

1610803442591.png

Warmup配置

默认 coldFactor为3,即请求QPS从( threshold/3)开始,经多少预热时长才逐渐升至设定的QPS阈值。

案例,阀值为10+预热时长设置5秒 系统初始化的阀值为10/3约等于3即阀值刚开始为3;然后过了5秒后阀值才慢慢升高恢复到10

1610803442619.png

测试

多次点击http://localhost:8401/testB

刚开始会出现访问错误,过了5s后才不会发生错误

1610803442685.gif

应用场景

如:秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是把为了保护系统,可慢慢的把流量放进来,慢慢的把值增长到设置的阈值

排队等待

匀速排队,阈值必须设置为QPS

官网

这种方式主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有大量的请求到来,而接来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,。而不是在第1s直接拒绝多余的请求

1610803442745.png

源码

com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController

配置

1610803442773.png

测试

1610803442816.png

查看控制台打印,你会发现1s打印一次,也就是说1s内只允许一个请求过来,其余请求请等待

1610803442872.png