《SpringCloud Alibaba 微服务架构》专题(十四)-Spring Cloud AlibabaSentinel之热点参数限流

1.引言

何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:

  • 商品ID为参数,统计一段时间内最常购买的商品ID并进行限制
  • 用户ID为参数,针对一段时间内频繁访问的用户ID进行限制

热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
在这里插入图片描述
Sentinel 利用LRU策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。热点参数限流支持集群模式。

2.热点参数规则

热点参数规则(ParamFlowRule)类似于流量控制规则(FlowRule

属性 说明 默认值
resource 资源名,必填
count 限流阈值,必填
grade 限流模式 QPS 模式
durationInSec 统计窗口时间长度(单位为秒),1.6.0 版本开始支持 模式 1s
controlBehavior 流控效果(支持快速失败和匀速排队模式),1.6.0 版本开始支持 快速失败
maxQueueingTimeMs 最大排队等待时长(仅在匀速排队模式生效),1.6.0 版本开始支持 0ms
paramIdx 热点参数的索引,必填,对应 SphU.entry(xxx, args) 中的参数索引位置
paramFlowItemList 参数例外项,可以针对指定的参数值单独设置限流阈值,不受前面 count 阈值的限制。仅支持基本类型和字符串类型
clusterMode 是否是集群参数流控规则 false
clusterConfig 集群流控相关配置

3.热点参数限流案例

前面我们已经了解了什么是热点参数限流,下面通过案例说明如何配置以及Sentinel是如何限流的。

【a】控制层添加如下方法

package com.bruce.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * @BelongsProject: springcloud-alibaba-nacos
 * @BelongsPackage: com.bruce.controller
 * @CreateTime: 2021-02-20 17:19
 * @Description: TODO
 */
@RestController
@Slf4j
public class HotKeyRuleController {
    
    

    /**
     * @SentinelResource: 指定资源名称,作用与HystrixCommand大体一致
     * blockHandler: 指定降级处理方法,类似于Hystrix的fallbackMethod兜底方法
     */
    @GetMapping("/testHotKeyRule")
    @SentinelResource(value = "testHotKeyRule", blockHandler = "testHotKeyRule_blockHandler")
    public String testHotKeyRule(@RequestParam(value = "username", required = false) String username,
                                 @RequestParam(value = "password", required = false) String password) {
    
    
        return "[热点限流规则]testHotKeyRule..";
    }

    public String testHotKeyRule_blockHandler(@RequestParam(value = "username", required = false) String username,
                                              @RequestParam(value = "password", required = false) String password,
                                              BlockException exception) {
    
    
        return "[热点限流规则-兜底方法]testHotKeyRule_blockHandler..";
    }

}

重启项目,浏览器访问: http://localhost:8401/testHotKeyRule
在这里插入图片描述
说明我们接口是通的,下面我们看看如何配置。

【b】Sentinel热点限流配置,具体配置如下图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
上面的配置表示:当访问testHotKeyRule资源的时候,针对方法testHotKeyRule的第一个参数【这里对应我们controller中的username参数】的请求,如果一秒内的请求阈值QPS超过1次,那么将会触发兜底方法。

浏览器访问: http://127.0.0.1:8401/testHotKeyRule?username=bruce
在这里插入图片描述
注意,这时候我们是一秒内访问一次,可以看到,接口正常返回数据。
突然,我们增加请求接口的频率,手动触发一秒内请求次数大于1次:
在这里插入图片描述
可见,当违反上面的配置请求规则时,马上降级处理,成功执行我们指定的blockHandler兜底方法。

下面我们访问:http://localhost:8401/testHotKeyRule?password=123456,注意这个请求并没有包含我们Sentinel配置的参数索引为0的参数【username】,不管我们一秒一次请求还是一秒内疯狂请求资源:
在这里插入图片描述
可以看到,当请求接口未包含指定的限流Key时,是不会触发blockHandler兜底方法的。

4.热点限流-参数例外项

前面我们介绍了普通版的热点参数限流,当第一个参数访问次数超过一秒钟一次后,达到阈值1后马上被限流,但我们有时候期望我们的限流参数Key当它是某个特殊值时,它的限流值和平时不一样。所以Sentinel提供了参数例外项的配置以满足这种特殊需求。

例如:假如前面我们的第一个参数username=bruce的时候,它的阈值可以达到500。
在这里插入图片描述
【a】Sentinel参数例外项配置
在这里插入图片描述
【b】测试

浏览器疯狂访问:http://localhost:8401/testHotKeyRule?username=bruce123
在这里插入图片描述

可以看到,当参数的值不满足例外项配置的值时,默认还是走普通的限流【一秒超过一次就直接降级】。

下面我们测试参数例外项: http://localhost:8401/testHotKeyRule?username=bruce

因为我们前面配置当参数的值等于"bruce"的时候,QPS阈值时500,所以当我们在浏览器一直刷新的时候,一秒钟内基本上不可能超过访问阈值500,所以也就不会触发降级方法。如下图所示:
在这里插入图片描述
下面我们说一个需要特别注意的地方,我们在业务方法里面模拟发生异常:

@GetMapping("/testHotKeyRule")
@SentinelResource(value = "testHotKeyRule", blockHandler = "testHotKeyRule_blockHandler")
 public String testHotKeyRule(@RequestParam(value = "username", required = false) String username,
                              @RequestParam(value = "password", required = false) String password) {
    
    
     int i = 10 / 0;
     return "[热点限流规则]testHotKeyRule..";
 }

重启项目,浏览器访问:http://localhost:8401/testHotKeyRule?username=bruce,
在这里插入图片描述
可以看到,直接将除数为0的报错展示出来了,并不会降级处理, 这里小伙伴们千万别搞错了, blockHandler兜底方法只针对你在Sentinel中配置的限流规则,当你违反了之后才会走兜底降级方法;如果是业务抛出的异常,Sentinel并不会降级处理。

小总结:

@SentinelResource:处理的是Sentinel控制台配置的违规情况,有blockHandler方法配置的兜底处理;

RuntimeException:java运行时抛出的运行时异常,@SentinelResource不管,@SentinelResource主管配置出错,运行该走异常还是走异常。

5.总结

热点参数限流规则主要是针对请求参数来统计,并实现限流的。首先热点参数是基于QPS统计,如果参数索引设置为0,则以第一个参数统计为准,阈值也是按照基本参数中的阈值来控制的,但是指定的是额外的参数列表的下标,则需要提供指定的热点参数的值,如果当前访问的参数与预设定的参数不一致,依旧与第一个参数的阈值为准。

猜你喜欢

转载自blog.csdn.net/BruceLiu_code/article/details/113898998