TypechoJoeTheme

香草物语

统计
登录
用户名
密码
/
注册
用户名
邮箱
输入密码
确认密码

Spring Cloud集成Sentinel之流量控制

Laughing博主
2021-07-28
/
0 评论
/
944 阅读
/
1735 个字
/
百度已收录
07/28
本文最后更新于2024年03月17日,已超过43天没有更新。如果文章内容或图片资源失效,请留言反馈,我会及时处理,谢谢!

Spring Cloud Alibaba sentinel的安装与配置中,我们介绍了Sentinel的功能以及安装部署方式。
Spring Cloud集成Sentinel之基础功能介绍中,我们介绍了如何在Spring Cloud中集成Sentinel。
本文我们在上面的基础上继续深入,介绍一下Sentinel的流量控制功能。

Sentinel流量控制介绍

流量控制(flow control),其原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。
FlowSlot会根据预设的规则,结合前面NodeSelectorSlotClusterNodeBuilderSlotStatisticSlot 统计出来的实时信息进行流量控制。
限流的直接表现是在执行 Entry nodeA = SphU.entry(resourceName) 的时候抛出 FlowException 异常。FlowExceptionBlockException 的子类,您可以捕捉BlockException来自定义被限流之后的处理逻辑。
同一个资源可以创建多条限流规则。FlowSlot会对该资源的所有限流规则依次遍历,直到有规则触发限流或者所有规则遍历完毕。
一条限流规则主要由下面几个因素组成,我们可以组合这些元素来实现不同的限流效果:
resource:资源名,即限流规则的作用对象
count: 限流阈值
grade: 限流阈值类型(QPS 或并发线程数)
limitApp: 流控针对的调用来源,若为 default 则不区分调用来源
strategy: 调用关系限流策略
controlBehavior: 流量控制效果(直接拒绝、Warm Up、匀速排队)

名词解释

  • 资源名:唯一名称、默认请求路径,也可以通过@SentinelResourcevalue属性指定,不可重复。
  • 针对来源:Sentinel可以针对调用者进行限流,填写微服务名,默认default(不区分来源)
  • 阀值类型/单机阀值:
    QPS(每秒钟的请求数量):当调用该api的QPS达到阀值的时候,进行限流线程数:当调用该api的线程数达到阀值的时候,进行限流
  • 是否集群:不需要集群
  • 流控模式:

    直接:api达到限流条件时,直接限流
    关联:当关联的资源达到阀值时,就限流自己
    链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阀值,就限流)【api级别的针对来源】

  • 流控效果:

    快速失败:直接失败,抛异常
    Warm Up:根据codeFactor(冷加载因子,默认3)的值,从阀值/codeFactor,经过预热时长,才达到设置的QPS阀值
    排队等待:匀速排队,让请求以均匀的速度通过,阀值类型必须设置为QPS,否则无效

代码展示

基于QPS的流量控制

QPS超过某个阈值的时候,则采取措施进行流量控制。流量控制的效果包括以下几种:直接拒绝、Warm Up、匀速排队。对应FlowRule中的 controlBehavior字段。
在代码中增加以下服务接口

 @GetMapping("/testQPSA")
    public String testA() {
        return "-----------testQPSA";
    }

如何此时我们不配置Sentinel,无论如何访问,都不会报错,流量会直接打到服务器,直到服务器崩溃。
此时,我们打开Sentinel,设置流控如下
配置的信息代表每秒最多允许一个请求,超过依次的请求直接报错。
此时我们快速刷新接口,可以看到以下信息

基于并发数的流量控制

基于并发数的控制,也就是控制同一时刻能够访问接口的数量。

 @GetMapping("/testThreadA")
    public String testThreadA() {
        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "-----------testThreadA";
    }

为了测试方便,我让程序暂停10S。
上图代表我们统一时刻只能有一个线程访问。
然后启动用浏览器及curl命令同时访问。
可以看到第一个浏览器能正常打开,但是curl命令的无法访问。

流控模式:直接

以上两个例子都是直接控制,也就是关联自己的资源。

流控模式:关联

当两个资源之间具有资源争抢或者依赖关系的时候,这两个资源便具有了关联。像对数据库同一个字段的读操作和写操作存在争抢,读的速度过高会影响写得速度,写的速度过高会影响读的速度。如果放任读写操作争抢资源,则争抢本身带来的开销会降低整体的吞吐量。
这次我们新增以下两个服务。

 @GetMapping("/testRelationA")
    public String testRelationA() {
        log.info(Thread.currentThread().getName() + "\t testRelationA");
        return "-----------testRelationA";
    }
    
    @GetMapping("/testRelationB")
    public String testRelationB() {
        log.info(Thread.currentThread().getName() + "\t testRelationB");
        return "-----------testRelationB";
    }

我们模拟:当testRelationB达到阈值时,停止testRelationA服务。
这次我们用JMeter进行测试,使用JMeter循环访问testRelationB
可以看到testRelationB访问一直正常,但是testRelationA此时已经不能访问了。

流控模式:链路

只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就可以限流)
这次我们删除所有的流控规则,查看sentinel我们可以看到/testRelationB的资源入口是sentinel_web_servlet_context
这次我们设置流控规则如下
多次点击http://localhost:8401/testRelationB,可以看到浏览器显示

流控效果:快速失败

以上代码都是直接快速失败的例子,当QPS超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出FlowException。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。

流控效果:Warm Up(预热)

Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。
我们增加以下代码。测试预测

@GetMapping("/testWarmup")
    public String testWarmup() {
        return "-----------testWarmup";
    }

以上表示,一开始系统QPS为1(3/3),10秒之后,系统QPS为3。
启用JMeter测试,设置请求100个,系统处理时间为50s,也就说1s发送两个请求。
可以看到,一开始,间隔成功一个、失败一个(因为我们JMeter设置的是1s处理两个请求,而Sentinel设置的是1s只能处理一个请求),10秒之后,就一直成功了(因为10s后,阈值为10,也就是说我们1s能处理10个请求,小于我们JMeter测试的一秒两个请求)

流控效果:排队等待

排队等待(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。
这种方式主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。

  @GetMapping("/testQueue")
    public String testQueue() {
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "-----------testQueue";
    }

一次处理一个请求,超时时间为20S,
使用JMeter默认10个请求
可以看到每个线程大概耗时都是1s。

Spring CloudSpring BootNacosSentinelSpring Cloud Alibaba
朗读
赞(0)
赞赏
感谢您的支持,我会继续努力哒!
版权属于:

香草物语

本文链接:

https://www.xiangcaowuyu.net/java/spring-cloud-integrates-sentinels-flow-control.html(转载时请注明本文出处及文章链接)

评论 (0)