Sentinel规则之热点参数限流规则
☞ 博客导航,带你有序的阅读和学习!
文档:
https://github.com/alibaba/Sentinel/wiki/%E7%83%AD%E7%82%B9%E5%8F%82%E6%95%B0%E9%99%90%E6%B5%81
概述
何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:
- 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
- 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。
热点参数规则
热点参数规则(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 | 集群流控相关配置 |
上面都是摘抄子官方网站,下面使用代码来测试。
我们先看一下热点参数规则的源码:
public class ParamFlowRule extends AbstractRule {
//限流模式
private int grade = RuleConstant.FLOW_GRADE_QPS;
//热点参数的索引
private Integer paramIdx;
//The threshold count.
private double count;
//流控效果
private int controlBehavior = RuleConstant.CONTROL_BEHAVIOR_DEFAULT;
//最大排队等待时长
private int maxQueueingTimeMs = 0;
private int burstCount = 0;
//统计窗口时间长度
private long durationInSec = 1;
//参数的额外项,可以针对指定的参数值单独设置限流阈值,不受前面的count影响,仅支持基本数据类型和字符串
private List<ParamFlowItem> paramFlowItemList = new ArrayList<ParamFlowItem>();
//额外参数
private Map<Object, Integer> hotItems = new HashMap<Object, Integer>();
//是否是集群参数流控规则 默认是false
private boolean clusterMode = false;
private ParamFlowClusterConfig clusterConfig;
}
public class ParamFlowItem {
private String object;//参数值
private Integer count;//限流阈值
private String classType;//参数类型
}
实验
初始化规则
public static void initParamFlowRule(){
List<ParamFlowRule> rules = new ArrayList<>();
ParamFlowRule rule = new ParamFlowRule();
//阈值类型:只支持QPS
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
//阈值
rule.setCount(1);
//资源名
rule.setResource("test");
rule.setParamIdx(0);//指配热点参数的下标
//统计窗口时间长度
rule.setDurationInSec(10);
List<ParamFlowItem> items = new ArrayList<>();
ParamFlowItem item = new ParamFlowItem();
item.setClassType(String.class.getTypeName());
item.setCount(2);
item.setObject("123456");//需要统计的值
ParamFlowItem item1 = new ParamFlowItem();
item1.setClassType(int.class.getName());
item1.setCount(3);
item1.setObject("12");
items.add(item);
items.add(item1);
rule.setParamFlowItemList(items);
rules.add(rule);
ParamFlowRuleManager.loadRules(rules);
}
上述初始化规则代码相当于按如下在控制台页面配置 :
逻辑代码
@GetMapping("/test")
public String test(
@RequestParam("username") String username,
@RequestParam("password") String password,
@RequestParam("age") int age) {
String echo = echoService.test(username,password,age);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
System.out.println(echo+" | t:"+dateFormat.format(new Date()));
return "访问成功";
}
public interface EchoService {
String test(String username, String password, int age);
}
@Service
public class EchoServiceImpl implements EchoService {
@Override
@SentinelResource(value = "test",blockHandler = "handleBlockForTest")
public String test(String username,String password, int age) {
return "username:"+username +" password:"+password + " age:"+age;
}
public String handleBlockForTest(String username, String password,int age, BlockException e){
return "username:"+username +" password:"+password +" age:"+age+"
e:"+e.getClass().getSimpleName();
}
}
测试1
localhost:8083/test?username=admin&password=123456&age=12
参数索引设置为:0
如果使用上述路径测试,结果为:
可以看出,passed的数量为1条,所以有效的阈值为1,统计的热点参数是username。
测试2
localhost:8083/test?username=admin&password=123456&age=12
参数索引设置为:1
可以看出,passed的数量为2条,所以有效的阈值为2,统计的热点参数,由于上面设置的为1,所以为password。
我们将password的123456修改一下,设置为12345,测试结果如下:
passed的条数为1条,所以在额外的参数不匹配时,阈值还原到了第一个热点参数:username。
总结
热点参数限流规则主要是针对请求参数来统计,并实现限流的。首先热点参数是基于QPS统计,如果参数索引设置为0,则以第一个参数统计为准,阈值也是按照基本参数中的阈值来控制的,但是指定的是额外的参数列表的下标,则需要提供指定的热点参数的值,如果当前访问的参数与预设定的参数不一致,依旧与第一个参数的阈值为准。