Spring Cloud Alibaba Sentinel之流控规则篇

一、简介

上一篇文章我们成功搭建了sentinel流量监控平台,并且实现了对我们微服务应用的监控功能,但是sentinel提供的功能不仅仅只有这些,还有强大的流量控制功能,本篇文章我们就将对流量控制做一个比较详细的总结。

二、相关术语

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

三、Sentinel流控模式 - QPS直接失败

QPS是什么?  简单理解,QPS就是每秒请求数量。

  • Sentinel的流控模式代表的流控的方式,默认【直接】,还有关联,链路。
  • Sentinel的流控效果:默认【快速失败】,还有WarmUp,排队等待。

下面我们通过一个示例说明QPS直接失败,具体配置如下:

【a】点击"簇点链路",查看当前有哪些资源可以进行流量控制

【b】新增QPS阈值,快速失败规则,具体配置见下图

添加完成后如下图:

 【c】测试

浏览器访问,http://localhost:8401/sentinel,我们控制1秒内只访问两次该接口:

 可以看到,在没有达到QPS(每秒请求两次)的阈值时,我们的/sentinel资源是正常访问的,下面我们疯狂点击,手动触发1秒内不止发起两个请求:http://localhost:8401/sentinel

可以看到,/sentinel资源被sentinel限流了,只要不超过QPS的阈值,接口是能够正常被访问的。

小总结:当调用该接口的QPS达到阈值的时候,进行限流。

四、Sentinel流控模式 - 线程数直接失败

【a】新增线程数阈值,快速失败规则,具体配置见下图

【b】改造/sentinel接口,增加模拟网络延时

@GetMapping("/sentinel")
    public String sentinel() {
        try {
            TimeUnit.MILLISECONDS.sleep(800);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "hello, sentinel dashboard....";
    }

【c】测试

打开两个浏览器窗口,分别访问:http://localhost:8401/sentinel,如果我们按照正常速度访问的话:

可以看到,是没有什么问题的,但当我们快速切换两个浏览器窗口时,疯狂点击刷新按钮,触发超过线程数阈值:

 可见,如果一秒内访问资源的线程数量超过1个,那么就会触发sentinel的限流。

小总结:当线程A过来访问该接口,该请求处理的很慢,还没有返回数据;此时线程B也过来访问该接口,线程B访问接口则会被限流;

五、Sentinel流控模式 - 关联

关联:当关联的资源达到阈值的时候,就限流自己,关联模式的核心就是保护关联资源的。举个例子,当与A关联的资源B达到阈值时,就限流A自己。

【a】因为要做资源关联,所以控制层新增如下方法

 @GetMapping("/sentinel2")
    public String sentinel2() {
        return "hello, sentinel dashboard....";
    }

【b】配置/sentinel资源关联/sentinel2资源,当/sentinel2资源达到阈值时,限流/sentinel资源。具体配置如下图:

 

【c】使用postman模拟密集访问/sentinel2资源

 

 【d】测试

当postman还在运行的时候,我们浏览器访问:http://localhost:8401/sentinel

可以看到,当/sentinel2资源达到阈值后,/sentinel资源就无法访问了,被限流,这就是关联。

分析:因为我们设置/sentinel资源关联/sentinel2资源,并且设置的QPS阈值为2,所以当1秒内访问/sentinel2的次数大于2时,/sentinel将会被限流,注意,并不是限制访问的自身资源(/sentinel2),而是/sentinel。(是不是感觉很霸道,关联资源达到阀值,是本资源接口被限流了)

这种关联模式有什么应用场景呢?

我们举个例子,订单服务中会有2个重要的接口,一个是读取订单信息接口,一个是写入订单信息接口。

在高并发业务场景中,两个接口都会占用资源,如果读取接口访问过大,就会影响写入接口的性能。业务中如果我们希望写入订单比较重要,要优先考虑写入订单接口。

那就可以利用关联模式:在关联资源上面设置写入接口,资源名设置读取接口就行了;这样就起到了优先写入,一旦写入请求多,就限制读的请求。

六、Sentinel流控模式 - 链路

链路流控模式指的是,当从某个接口过来的资源达到限流条件时,就开启限流;

上面的解释有点模糊,我们需要改造一下代码。

【a】新增业务层接口

package com.wsh.springcloud.alibaba.service;


import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

@Service
public class SentinelService {

    private static final Logger logger = LoggerFactory.getLogger(SentinelService.class);

    /**
     * @SentinelResource: 可以理解就是一个资源名
     */
    @SentinelResource("sentinelChain")
    public String sentinelChain() {
        logger.info("测试Sentinel流控模式 - 链路模式");
        return "Sentinel Mode - Chain";
    }

}

【b】控制层新增两个方法,都是调用上面的业务方法

 @Autowired
    private SentinelService sentinelService;

    @GetMapping("/testA")
    public String testA() {
        logger.info("SentinelController>>>>>testA() execute....");
        return sentinelService.sentinelChain();
    }

    @GetMapping("/testB")
    public String testB() {
        logger.info("SentinelController>>>>>testB() execute....");
        return sentinelService.sentinelChain();
    }

【c】Sentitel链路配置

下面我们就可以利用链路模式设置限制哪个入口的流量了,具体配置如下图:

注意:

  从1.6.3 版本开始, Sentinel Web filter默认收敛所有URL的入口context,因此链路限流不生效; ​

  1.7.0 版本开始(对应Spring Cloud Alibaba的2.1.1.RELEASE),官方在CommonFilter 引入了WEB_CONTEXT_UNIFY 参数,用于控制是否收敛context;将其配置为 false 即可根据不同的URL 进行链路限流;

@Configuration
public class FilterContextConfig {
    @Bean
    public FilterRegistrationBean sentinelFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new CommonFilter());
        registration.addUrlPatterns("/*");
        // 入口资源关闭聚合
        registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false");
        registration.setName("sentinelFilter");
        registration.setOrder(1);
        return registration;
    }
}

具体可以参考:

https://github.com/alibaba/Sentinel/issues/1411

https://github.com/alibaba/Sentinel/issues/1313

https://github.com/alibaba/Sentinel/issues/1213 

https://github.com/alibaba/Sentinel/issues/1213#issuecomment-5683614283

由于我们Spring Cloud Alibaba使用的是2.1.0.RELEASE版本,CommonFilter暂时还没有WEB_CONTEXT_UNIFY属性,所以这里就不演示链路流控了,有兴趣的小伙伴可以升级到spring-cloud-alibaba v2.1.1.RELEASE以后的版本试一下。

小总结:链路的功能有点类似于针对来源配置项,区别在于:针对来源是针对上级微服务,而链路流控是针对上级接口,也就是说它的粒度更细。

七、Sentinel流控效果 - 快速失败

快速失败也是默认的Sentinel流控效果,在前面的示例中已经介绍,这里不过分阐述。

八、Sentinel流控效果 - 预热(Warm Up)

【a】限流、冷启动概述

当流量突然增大的时候,我们常常会希望系统从空闲状态到繁忙状态的切换的时间长一些。即如果系统在此之前长期处于空闲的状态,我们希望处理请求的数量是缓步的增多,经过预期的时间以后,到达系统处理请求个数的最大值。Warm Up(冷启动,预热)模式就是为了实现这个目的的。

这个场景主要用于启动需要额外开销的场景,例如建立数据库连接等。

它的实现是在 Guava 的算法的基础上实现的。然而,和 Guava 的场景不同,Guava 的场景主要用于调节请求的间隔,即 Leaky Bucket,而 Sentinel 则主要用于控制每秒的 QPS,即我们满足每秒通过的 QPS 即可,我们不需要关注每个请求的间隔,换言之,我们更像一个 Token Bucket

我们用桶里剩余的令牌来量化系统的使用率。假设系统每秒的处理能力为 b,系统每处理一个请求,就从桶中取走一个令牌;每秒这个令牌桶会自动掉落b个令牌。令牌桶越满,则说明系统的利用率越低;当令牌桶里的令牌高于某个阈值之后,我们称之为令牌桶"饱和"。

通常冷启动的过程系统允许通过的 QPS 曲线如下图所示:

在这里插入图片描述

QPS阈值除以coldFactor(默认值为3),经过预热时长后才会达到阈值。默认 coldFactor 为 3,即请求 QPS 从 threshold / 3 开始,经预热时长逐渐升至设定的 QPS 阈值。

【b】WarmUp配置,具体配置如下图:

添加完成后如下图所示: 

【c】测试

我们浏览器访问:http://localhost:8401/sentinel2,在访问开始的5秒钟之前,此时QPS还没达到阈值10,我们疯狂点击,因为sentinel还在预热阶段,所以访问结果如下:

 可见,此时接口是会被sentinel限流的。

当过了5秒后,sentinel预热完成,QPS也恢复到阈值10,所以此时我们再次疯狂访问:http://localhost:8401/sentinel2时,接口是不会被sentinel限流的,当然,前提是一秒钟之内访问次数不能超过阈值10。

分析:因为我们设置的是QPS阈值是10,预热时长是5秒钟,系统初始化刚开始的时候阈值是10 / 3 = 约等于3,然后过了5秒钟后,系统阈值将会恢复升高到我们设置的阈值10。 

应用场景:秒杀系统的开启瞬间,会有很多流量上来,很可能会把系统打挂,预热方式就是为了保护系统,可以慢慢的把流量放进来,慢慢的把阈值增长到设定的阈值。

九、Sentinel流控效果 - 排队等待

【a】概述

排队等待指的是严格控制请求通过的时间间隔,也即是让请求以均匀的速度通过,对应的是漏桶算法。

排队等待的作用如下图所示:

在这里插入图片描述

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

【b】新增一个接口用于测试排队等待

  @GetMapping("/sentinel3")
    public String sentinel3() {
        logger.info(Thread.currentThread().getName() + ">>>>>>sentinel3");
        return "hello, sentinel dashboard....";
    }

【c】排队等待配置,具体如下图

【d】借助postman循环访问/snetinel3这个资源

【e】测试结果

我们看看控制台的日志输出:

2020-09-03 11:45:50.096  INFO 25352 --- [io-8401-exec-10] c.w.s.a.controller.SentinelController    : http-nio-8401-exec-10>>>>>>sentinel3
2020-09-03 11:45:51.095  INFO 25352 --- [nio-8401-exec-6] c.w.s.a.controller.SentinelController    : http-nio-8401-exec-6>>>>>>sentinel3
2020-09-03 11:45:52.095  INFO 25352 --- [nio-8401-exec-9] c.w.s.a.controller.SentinelController    : http-nio-8401-exec-9>>>>>>sentinel3
2020-09-03 11:45:53.095  INFO 25352 --- [nio-8401-exec-8] c.w.s.a.controller.SentinelController    : http-nio-8401-exec-8>>>>>>sentinel3
2020-09-03 11:45:54.097  INFO 25352 --- [nio-8401-exec-3] c.w.s.a.controller.SentinelController    : http-nio-8401-exec-3>>>>>>sentinel3
2020-09-03 11:45:55.097  INFO 25352 --- [nio-8401-exec-2] c.w.s.a.controller.SentinelController    : http-nio-8401-exec-2>>>>>>sentinel3
2020-09-03 11:45:56.096  INFO 25352 --- [nio-8401-exec-1] c.w.s.a.controller.SentinelController    : http-nio-8401-exec-1>>>>>>sentinel3
2020-09-03 11:45:57.095  INFO 25352 --- [nio-8401-exec-7] c.w.s.a.controller.SentinelController    : http-nio-8401-exec-7>>>>>>sentinel3
2020-09-03 11:45:58.097  INFO 25352 --- [nio-8401-exec-4] c.w.s.a.controller.SentinelController    : http-nio-8401-exec-4>>>>>>sentinel3
2020-09-03 11:45:59.095  INFO 25352 --- [nio-8401-exec-5] c.w.s.a.controller.SentinelController    : http-nio-8401-exec-5>>>>>>sentinel3

我们可以发现请求每隔1秒执行一次,这么多的请求没有被拒绝,而且进入的排队。

分析:因为我们设置的QPS阈值是1,表示一秒内只能有一个请求,但是我们Postman测试0.3秒发起一个请求,很明显超过阈值后,并没有触发sentinel限流,而是一个一个匀速执行。

排队的应用场景是什么呢?

比如有时候系统在某一个时刻会出现大流量,之后流量就恢复稳定,可以采用这种排队模式,大流量来时可以让流量请求先排队,等恢复了在慢慢进行处理

十、总结

Sentinel的流控方式还是比较实用的,功能比较强大,小伙伴们一定要自己搭建项目亲手试一下,毕竟实践出真知。以上相关项目的代码我已经放在Gitee上,有需要的小伙伴可以去拉取进行学习:https://gitee.com/weixiaohuai/springcloud_Hoxton,由于笔者水平有限,如有不对之处,还请小伙伴们指正,相互学习,一起进步。

参考资料:

https://github.com/alibaba/Sentinel/wiki/%E9%99%90%E6%B5%81---%E5%86%B7%E5%90%AF%E5%8A%A8

下面是笔者总结的关于Spring Cloud Alibaba教程系列文章目录,有需要的小伙伴可以前往学习:

1. Spring Cloud Alibaba入门简介

2. Spring Cloud Alibaba Nacos之服务注册中心

3. Spring Cloud Alibaba Nacos之服务配置中心

4. Spring Cloud Alibaba Nacos集群和持久化配置

5. Spring Cloud Alibaba Sentinel之入门篇

6. Spring Cloud Alibaba Sentinel之流控规则篇

7. Spring Cloud Alibaba Sentinel之服务降级篇

8. Spring Cloud Alibaba Sentinel之热点参数限流篇

9. Spring Cloud Alibaba @SentinelResource配置详解

10. Spring Cloud Alibaba Sentinel之服务熔断篇

11. Spring Cloud Alibaba Sentinel之持久化篇

12. Spring Cloud Alibaba Seata处理分布式事务及案例实战

13. Spring Cloud Alibaba Seata工作原理

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页
实付 19.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值