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 |
集群流控相关配置 |
|
上面都是摘抄子官方网站,下面使用代码来测试。
我们先看一下热点参数规则的源码:
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
| public class ParamFlowRule extends AbstractRule { private int grade = RuleConstant.FLOW_GRADE_QPS;
private Integer paramIdx;
private double count;
private int controlBehavior = RuleConstant.CONTROL_BEHAVIOR_DEFAULT; private int maxQueueingTimeMs = 0; private int burstCount = 0; private long durationInSec = 1;
private List<ParamFlowItem> paramFlowItemList = new ArrayList<ParamFlowItem>();
private Map<Object, Integer> hotItems = new HashMap<Object, Integer>();
private boolean clusterMode = false; private ParamFlowClusterConfig clusterConfig; }
public class ParamFlowItem { private String object; private Integer count; private String classType; }
|
实验
初始化规则
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
| public static void initParamFlowRule(){ List<ParamFlowRule> rules = new ArrayList<>(); ParamFlowRule rule = new ParamFlowRule(); 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); }
|
上述初始化规则代码相当于按如下在控制台页面配置 :
逻辑代码
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
| @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
1 2
| localhost:8083/test?username=admin&password=123456&age=12 参数索引设置为:0
|
如果使用上述路径测试,结果为:
可以看出,passed的数量为1条,所以有效的阈值为1,统计的热点参数是username。
测试2
1 2
| localhost:8083/test?username=admin&password=123456&age=12 参数索引设置为:1
|
可以看出,passed的数量为2条,所以有效的阈值为2,统计的热点参数,由于上面设置的为1,所以为password。
我们将password的123456修改一下,设置为12345,测试结果如下:
passed的条数为1条,所以在额外的参数不匹配时,阈值还原到了第一个热点参数:username。
总结
热点参数限流规则主要是针对请求参数来统计,并实现限流的。首先热点参数是基于QPS统计,如果参数索引设置为0,则以第一个参数统计为准,阈值也是按照基本参数中的阈值来控制的,但是指定的是额外的参数列表的下标,则需要提供指定的热点参数的值,如果当前访问的参数与预设定的参数不一致,依旧与第一个参数的阈值为准。