流控模式

流控模式分为三种:直接、关联和链路

直接

直接就是只限制单个资源,可以是接口,也可以是标记了 @SentinelResource 注解的 Service 方法。

image-20221105145131440

关联

关联就是 A 资源把 B 资源关联了,A 资源的访问次数多了会影响到 B 资源的访问,类似于连带的意思。/order/get 可以看作时 B 资源,/order/add 可以看作时 A 资源,配置如下所示。

image-20221105140617122

链路

链路流控,比如有 A、B、C 三个资源,A 和 B 依赖于 C,类似于树结构。

  C
 / \
A   B 

然后我需要对 B 进行限流,流量太多的原因是来自于 C,所以我要在 C -> B 这条链路中对 C 进行限流。这里假设 C 为 getUser,A 为 /order/test1,B 为 /order/test2,配置应如下所示。

image-20221105143837034

在 sentinel 1.6 之后,链路的维护是关闭的,也就是合在一起(unify)的。需要在配置文件中配置一下。

spring.cloud.sntinel.web-context-unify=false # 默认不维护调用链路,关闭收敛

服务重启之后,再重新去配置一下 getUser 的流控,限制入口资源为 /order/test2。当我访问 /order/test2 的时候,则触发流控异常,访问 /order/test1 ,由于限制的入口为 /order/test2,不会触发异常。

流控效果

流控效果分为 3 种:快速失败、Warm Up、排队等待

快速失败

快速失败,当超过了设置的阈值时,超过部分会被拒绝,即抛流控异常。异常可以配置全局的和局部的,全局的异常需要去实现 BlockExceptionHandler 接口来处理。局部的异常需要在 @SentinelResource 注解中指定 blockHandler 属性,一般就是本类中的方法,且方法必须为 public、返回值也一定和接口、方法名中的返回值一致。

@GetMapping("/flowthread")
@SentinelResource(value = "flow", blockHandler = "flowBlockHandler")
public String flowThread() throws InterruptedException {
    Thread.sleep(10000);
    return "正常访问thread";
}

public String flowBlockHandler(BlockException e) {
    return "流控了!";
}

若在其它类中则指定 blockHandlerClass

Warm Up

Warm Up 又称预热/冷启动。当一个服务处于低流量的时候,突然流量激增可能会导致服务响应慢甚至是崩溃,为了能够抵御住突如其来的流量时,在到达阈值之后,在规定的时间将服务预热,让通过的流量缓慢增加,这样就不会出现服务宕机的问题了。

说起来有点费劲,但是通过这张图就能感觉到了。

image-20221105233519118

在 sentinel 中,默认的冷加载因子(codeFactor)为 3,QPS = threshold(阈值)/ 3,随着访问增多,经预热时长逐渐升至设定的 QPS 阈值。

在上图的预热截图中,对应的配置如下图所示。

image-20221105233700340

排队等待

排队等待适用于间隔性的突发流量,也就是在某一秒有大量间隔,然后几秒的时间空闲,然后又有突发流量涌入。例如消息队列。

这里使用了 JMeter 测试工具模拟间隔性突发流量的情况,QPS 数超过 5 时,直接拒绝掉。

image-20221118181403061

我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是拒绝掉,所以我们可以编辑流控规则,将流控效果设置成“排队等待”,且设置排队超时时间为 5 秒。

image-20221115152545286

设置之后的效果,QPS 全部通过,因为后端有能力能在 5 秒内将逻辑处理完。

image-20221118182052728