目录

springcloudAlibaba_sentinel 流控

流控规则

流控官网说明

http://img.cana.space/picStore/20201115110433.png

一条限流规则主要由下面几个因素组成,我们可以组合这些元素来实现不同的限流效果:

  • resource:资源名,即限流规则的作用对象;名称唯一,默认请求路径
  • count: 限流阈值
  • grade: 限流阈值类型(QPS 或并发线程数)
    • QPS:当调用该api的qps超过阈值的时候进行限流
    • 线程数:当调用该api的线程数超过阈值的时候进行限流
  • limitApp: 流控针对的调用来源,若为 default 则不区分调用来源
  • strategy: 流控模式,调用关系限流策略
    • 直接:api达到限流条件时,直接限流
    • 关联:当关联的资源达到阈值时,就限流自己
    • 链路:只限制指定链路上的流量,指定资源从入口资源进来的流量,如果达到阈值就进行限流(api级别的针对来源)
  • controlBehavior: 流量控制效果(直接拒绝、Warm Up、匀速排队)
    • 快速失败:直接失败,抛异常
    • Warm Up:根据codeFactor(冷加载因子,默认3)的值,从阈值/codeFactor,经过预热时长,才达到设置的qps阈值
    • 排队等待:匀速排队方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。

如何加流控规则

  1. 流控规则->新增流控规则
  2. 簇点链路->对某个链路 +流控 (推荐)

流控模式

直接

QPS直接失败(默认)

新增流控规则

http://img.cana.space/picStore/20201115111956.png

先按照1s一次正常访问http://localhost:8401/hello

狂刷结果:

http://img.cana.space/picStore/20201115112048.png

编辑流控规则qps阈值到100,再次狂刷,发现修改的规则已生效。

思考

直接调用报默认错信息,技术方面OK but,是否应该有我们自己的后续处理,类似豪猪的fallback兜底方法

线程数直接失败

  1. 改造服务接口,如下

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    @SpringBootApplication
    public class ServiceMain8401 {
        public static void main(String[] args) {
            SpringApplication.run(ServiceMain8401.class, args);
        }
       
        @RestController
        public class TestController {
       
            @GetMapping(value = "/hello")
            @SentinelResource("hello")
            public String hello() throws InterruptedException {
                 // sleep 3秒,让应用程序同时存在多个线程
                TimeUnit.SECONDS.sleep(3);
                return "Hello Sentinel";
            }
        }
    }
    
  2. 添加线程数直接失败流控规则

    http://img.cana.space/picStore/20201115120536.png

  3. 狂刷:http://localhost:8401/hello

qps和线程数流控两种方式比较

  • qps:御敌于国门之外,还没进到应用里面
  • 线程数:关门打狗,进到应用里面但是线程数需要在控制范围内

关联

别人惹事我买单

应用场景:在分布式应用链路中,应用之间是相互影响的,下游(这里使用/world模拟下游)压力大,需要限制上游(/hello)流量

  1. 改造主启动类

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    
    package com.eh.cloudalibaba.sentinel;
       
    import com.alibaba.csp.sentinel.annotation.SentinelResource;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
       
    @SpringBootApplication
    public class ServiceMain8401 {
        public static void main(String[] args) {
            SpringApplication.run(ServiceMain8401.class, args);
        }
       
        @RestController
        public class HelloController {
       
            @GetMapping(value = "/hello")
            @SentinelResource("hello")
            public String hello() {
                return "Hello Sentinel";
            }
        }
       
        @RestController
        public class WorldController {
       
            @GetMapping(value = "/world")
            @SentinelResource("world")
            public String hello() {
                return "World Sentinel";
            }
        }
    }
    
  2. 配置关联流控规则

    当资源/world超过阈值时,/hello就会被限流

    http://img.cana.space/picStore/20201115121524.png

  3. 验证

    当下游(/world)qps超过阈值,上游(/hello)限流

    使用jmeter模拟下游qps超过1的情况,如下:

    1. 增加吞吐量定时器,吞吐量控制在1个线程每秒60次请求

      http://img.cana.space/picStore/20201115123408.png

    2. 设置线程数和启动限制时间

      http://img.cana.space/picStore/20201115123504.png

    3. 设置请求

      http://img.cana.space/picStore/20201115123526.png

    4. 检查请求速率

      http://img.cana.space/picStore/20201115123601.png

    5. 访问上游("/hello")

      http://img.cana.space/picStore/20201115123628.png

    6. 关闭jmeter下游请求,再次访问上游

      http://img.cana.space/picStore/20201115123707.png

链路

链路的控制指的就是对一条链路的访问进行控制。

比方说,有一个二叉树:

a
/ \
b c
/ | | \
d e f g

a->b->d, a->b->e, a->c->f, a->c->g均可视作链路。假设我以a为入口资源,d为终点资源,对这条链路进行限制的话,则资源a,b,d均会被限制访问。

20201115123922

流控效果

快速失败

默认的流控处理,直接失败,抛出异常Blocked by Sentinel (flow limiting)

源码

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

预热(Warm Up)

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

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

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

http://img.cana.space/picStore/20201115125708.png

源码

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

应用场景

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

演示

  1. 配置流控效果,5秒内达到10

    http://img.cana.space/picStore/20201115130334.png

  2. 设置jemete进行访问,qps 10

  3. 验证

    http://img.cana.space/picStore/20201115130249.png

    可以看到流控从qps为3在5s内慢慢增加到10,最后都能正常访问,这就是流控的预热效果

排队等待

匀速排队(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。详细文档可以参考 流量控制 - 匀速器模式,具体的例子可以参见 PaceFlowDemo

该方式的作用如下图所示:

http://img.cana.space/picStore/20201115131228.png

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

注意:匀速排队模式暂时不支持 QPS > 1000 的场景。

演示:

  1. 配置匀速排队模式流控规则,单机阈值10,超时时间10s

    http://img.cana.space/picStore/20201115131453.png

  2. 设置jemeter,吞吐量20,应该全部正确,如下

    http://img.cana.space/picStore/20201115132826.png

    可以看到实际吞吐量被限制了,使用的漏桶算法。