guava RateLimiter 源码解析-非预热

it2022-05-05  203

一、非预热

1、创建limiter,参数为QPS,允许每秒的流量(即每秒产生的令牌数)

接着跟进方法,可以看到stableIntervalMicros为产生令牌的时间间隔

继续,最大令牌数等于permitsPersecond,maxBurstSeconds默认为1,接着初始化桶内令牌数量,如果原来最大令牌数为正无穷,则初始化令牌数为新的最大令牌数(不知道什么场景下会出现这个),如果原来最大令牌数为0,则初始化令牌数为0,否则计算(这里也不知道什么情况会出现),至此limiter初始化完毕.

 

2、获取令牌;分为两步,第一步,获取本次需要等待的时间,第二步,线程sleep

 

获取等待时间,此处锁定了一个volatile的单例对象,以保证同步获取令牌,采用双重验证懒加载了单例对象

获取等待时间的核心方法,第一步刷新令牌数量和下次生成令牌的时间,第二步扣减令牌数,返回一个时间

刷新令牌数量:如果当前时间大于下次生成令牌的时间,说明有令牌可以生成,用时间差除以生成间隔,得到生成的令牌数量,更新存储的令牌数、下次生成令牌的时间节点

返回时间取值为当前时间(如果当前时间大于下次生成令牌的时间)或下次生成令牌的时间(如果当前时间小于下次生成令牌时间),

此处可以看出令牌是可以预支使用的,本次预支的令牌会到下次获取令牌时等待生成获取;freshPermits值为0(当存储的令牌足够本次使用)或差异值(存储的令牌不够本次使用),waitMicros值为生成差的令牌数需要的时间,并累加到下次生成令牌的时间上(即这段时间的令牌已经被预支了)

回到上层,最终返回的等待是时间为距离下次令牌生成时间的值,线程会sleep到下次生成令牌的时间点。

 

总结:非预热的限流是预支类型,如果令牌足够,可以一直获取令牌,令牌不够的时候,会先预支获取令牌,将令牌生成时间推后到补齐预支令牌的时间,如果下次获取令牌的时间在这之前,那么就需要等待。因此这种限流是允许一定突发的流量,桶中的令牌数可以被消耗成负数。


最新回复(0)