RateLimiter限流源码分析
主要从以下几个方面进行分析
RateLimiter工作原理的总体介绍
首先RateLimiter是goole 出品的一个基于令牌桶算法的一个组件,其中有两种模式(XSmoothBursty和XSmoothWarmingUp),XSmoothBursty是以恒定速率生成令牌,也就是平滑模式,比如1秒生成5个令牌,那么就是200微秒产生一个令牌。而SmoothWarmingUp代表渐进模式,当速率变大到一定程度后趋于平衡,该模式可以应对突发流量的情况发生。
RateLimiter支持提前消费的概念,比如我每次只能挣5块钱,但是我买东西要花费6块钱,那怎么办呢,我可以通过向老板预支11块钱钱去购买东西,那下一次我还是要买6块钱的东西,那我就得等把上一次的1块钱先还掉才能进行下一次发工资,而挣这一块钱所花费的时间+本身挣5块钱所花费的时间就是我等待的时间,具体数据后面会通过大量的测试进行验证,包括其他情况。
RateLimiter的继承关系(基类与子类的关系图)
RateLimiter是一个抽象类,目前只有一个子类SmoothRateLimiter,而SmoothRateLimiter也是一个抽象类,在SmoothRateLimiter下有两个实现子类,一个是SmoothBursty,一个是SmoothWarmingUp。
关键属性字段分析
RateLimiter中的字段解析
stopwatch | 时间计算器,这里采用的微秒计时,后面用来计算还有多长时间获取令牌时用 |
---|---|
mutexDoNotUseDirectly | 对象锁,设置速率时,线程安全保护,避免临界资源竞争,此处采用的双重锁检查的单列模式来生成的锁 |
SmoothRateLimiter中的字段解析
storedPermits | 剩余的令牌数 |
---|---|
maxPermits | 表示最大允许的令牌数 |
stableIntervalMicros | 每隔多长时间产生一个令牌,采用的时间是微秒 |
– | – |
nextFreeTicketMicros | 表示下一次可以获取令牌的时间,此处是一个相对时间 |
SmoothBursty中的字段分析
·maxBurstSeconds | 表示如果你很久没有请求,但是令牌数不会随着时间推移而增加,而是只缓存1秒的时间的令牌 |
---|---|
SmoothWarmingUp中的字段分析
warmupPeriodMicros | |
---|---|
slope | |
thresholdPermits | |
– | – |
coldFactor |
核心方法分析(创建—>申请)
SmoothBursty模式创建RateLimiter的过程(时序图)
- 在RateLimiter这个抽象类中有创建RateLimiter对象的两个静态方法create(),根据不同的入参获取到具有相应模式的RateLimiter对象,比如创建一个SmoothBursty模式并每秒产生2个令牌的RateLimiter限流器。
//入参必须是大于0的数,不然会抛rate must be positive 异常
RateLimiter rateLimiter = RateLimiter.create(2);
- 进入create方法中,我们发现,做了两件事,第一件事:通过内部类SmoothBursty实例化了一个RateLimiter限流器,入参为:stopwatch(计时器对象)和maxBurstSeconds(最大缓存秒数)第二件事: 设置生成令牌的速率的setRate方法。
static XRateLimiter create(double permitsPerSecond, XRateLimiter.SleepingStopwatch stopwatch) {
XRateLimiter rateLimiter = new XSmoothRateLimiter.XSmoothBursty(stopwatch, 1.0 /* maxBurstSeconds */);
System.out.println("permitsPerSecond:"+permitsPerSecond);
//创建限流器的时候,进行获取令牌的速度设置, 此次有点类似于信号量
rateLimiter.setRate(permitsPerSecond);
return rateLimiter;
}
- 进入setRate方法进行速率设置,在这个方法中,通过锁机制进入doSetRate方法…先调用resync方法进行初始的数据计算,比如:当此刻计时器的数据大于下一次获取令牌的时间(此刻时间为0)的情况下,开始计算storedPermitsd的值和nextFreeTicketMicros的值。
void resync(long nowMicros) {
if (nowMicros > nextFreeTicketMicros) {
double newPermits = (nowMicros - nextFreeTicketMicros) / coolDownIntervalMicros();
storedPermits = min(maxPermits, storedPermits + newPermits);
nextFreeTicketMicros = nowMicros;
}
}
- 接下来设置stableIntervalMicros的值(也就是每多少时间产生一个令牌),并设置最大令牌数maxPermits的值,以及更新storedPermits的值。
//计算出旧的最大许可存储量
double oldMaxPermits = this.maxPermits;
//获取新的最大的许可存储量(按照秒计算)
maxPermits = maxBurstSeconds * permitsPerSecond;
//如果旧的最大许可为无限大的情况,那么没有被使用的许可数量也是无限多
if (oldMaxPermits == Double.POSITIVE_INFINITY) {
storedPermits = maxPermits;
//如果不是无限多的话,就重新计算还有多少个许可令牌数
} else {
storedPermits = (oldMaxPermits == 0.0)? 0.0 : storedPermits * maxPermits / oldMaxPermits;
}