桥泰

导航

 

热点参数限流


根据参数进行限流,对每个参数分别限流(比如orderId=100,101不同参数)
参数索引,从0开始,0就是第一个参数
单机阈值:5 统计窗口时长:1,表示1秒允许通过5个
ParamFlowSlot
com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowSlot#entry
com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager#hasRules
有限流规则,执行this.checkFlow(resourceWrapper, count, args);
检测参数为null,直接返回 ===》
com.alibaba.csp.sentinel.adapter.spring.webmvc.AbstractSentinelInterceptor#preHandle
Entry entry = SphU.entry(resourceName, ResourceTypeConstants.COMMON_WEB, EntryType.IN);
没有传入参数,也就是controller资源是没有办法做热点参数

只有SentinelResource注解的资源可以做热点参数限流
com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect#invokeResourceWithSentinel,创建资源时,方法中传入了参数
entry = SphU.entry(resourceName, resourceType, entryType, pjp.getArgs());

 

 

 

com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowSlot#entry
checkFlow
this.applyRealParamIdx(rule, args.length);

初始化令牌桶,有就获取,没有就创建
ParameterMetricStorage.initParamMetricsFor(resourceWrapper, rule);

检查
ParamFlowChecker.passCheck(resourceWrapper, rule, count, args)

不是集群,进入单机passSingleValueCheck()
passDefaultLocalCheck()

进入真正的校验检查,
获取令牌桶,ParameterMetric metric = getParameterMetric(resourceWrapper);

<值(传入的参数),计数器>,表示当前还剩下多少个令牌,来一个就扣减1个,记录令牌
CacheMap<Object, AtomicLong> tokenCounters
最近通过的一次请求时间,记录时间,是一种时间的long值
CacheMap<Object, AtomicLong> timeCounters
算法思路:
时间差(本次统计开始时间 - 上一次统计结束时间)

时间差/统计窗口时长 * 单机阈值 = 需要往令牌桶里面补充的令牌(也就是计数)
比如时间差为3秒 统计窗口时长为1秒 单机阈值为5
那么就是 3/1*5=15,应该有15个令牌,算法控制会更加精细,会限制为1个时间范围的统计区间

平常不生产,而是你来了就生产

获取限流规则
Set<Object> exclusionItems = rule.getParsedHotItems().keySet();

rule.getBurstCount()这个是获取突发阈值
acquireCount 需要的令牌数量

之前没有来过,先创建一个新的,并且扣减要求的令牌数,存入tokenCounters。
long currentTime = TimeUtil.currentTimeMillis();
AtomicLong lastAddTokenTime = (AtomicLong)timeCounters.putIfAbsent(value, new AtomicLong(currentTime));
if (lastAddTokenTime == null) {
tokenCounters.putIfAbsent(value, new AtomicLong(maxCount - (long)acquireCount));
return true;
}

rule.getDurationInSec() 单位:秒,【统计窗口时长:秒】
1、如果超过时间窗口时长,那么进入计算
AtomicLong oldQps = (AtomicLong)tokenCounters.putIfAbsent(value, new AtomicLong(maxCount - (long)acquireCount));
如果value有值,就返回有值给oldQps,如果没有值,那么就是重新设置后,返回null给oldQps
2、如果在时间窗口,那么就扣减要求的令牌后,返回true

oldQps不为null
long toAddCount = passTime * tokenCount / (rule.getDurationInSec() * 1000L);
计算出这段时间内,应该生成多少个令牌

累计生成令牌数量+剩余的令牌数量如果超过令牌桶的最大maxCount,那么maxCount - (long)acquireCount,否则,使用restQps + toAddCount - (long)acquireCount。
long newQps = toAddCount + restQps > maxCount ? maxCount - (long)acquireCount : restQps + toAddCount - (long)acquireCount;
如果 if (newQps < 0L) {,返回false,进行限流,否则放行

Thread.yield() 方法是Java中的一个静态方法,用于提示线程调度器当前线程愿意让出 CPU 使用权,从而使得其他具有相同或更高优先级的线程有机会执行‌‌


 

posted on 2025-06-10 22:57  桥泰  阅读(16)  评论(0)    收藏  举报