1.引言
何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:
有需要了解分布式微服务电商源码的朋友可以微信我: 445909108
商品ID为参数,统计一段时间内最常购买的商品ID并进行限制
用户ID为参数,针对一段时间内频繁访问的用户ID进行限制
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
Sentinel 利用LRU策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。热点参数限流支持集群模式。
2.热点参数规则
热点参数规则(ParamFlowRule)类似于流量控制规则(FlowRule)
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,则以第一个参数统计为准,阈值也是按照基本参数中的阈值来控制的,但是指定的是额外的参数列表的下标,则需要提供指定的热点参数的值,如果当前访问的参数与预设定的参数不一致,依旧与第一个参数的阈值为准。