1. RateLimiter基于令牌桶算法,即以用户设定的恒定速率向令牌桶内放置令牌,用户来执行任务时,只有拿到令牌才能执行;
2. RateLimiter对于持续生成令牌,采用的不是定时任务的方式(过于耗费资源,不适合高并发),而是使用延迟计算的方式,即在获取令牌时计算上一次时间nextFreeTicketMicros和当前时间之间的差值,计算这段时间之内按照用户设定的速率可以生产多少令牌;
-
void resync(long nowMicros) {
-
// if nextFreeTicket is in the past, resync to now
-
if (nowMicros > nextFreeTicketMicros) {
-
double newPermits = (nowMicros - nextFreeTicketMicros) / coolDownIntervalMicros();//能够生产多少令牌
-
storedPermits = min(maxPermits, storedPermits + newPermits);
-
nextFreeTicketMicros = nowMicros;//修改时间
-
}
-
}
3. RateLimiter计算延迟时间,即过度消费部分需要由下一次调用买单,因此其具有处理突发流量的能力(就和花呗一样);
-
final long reserveEarliestAvailable(int requiredPermits, long nowMicros) {
-
resync(nowMicros);
-
long returnValue = nextFreeTicketMicros; // 返回的是上次计算的nextFreeTicketMicros
-
double storedPermitsToSpend = min(requiredPermits, this.storedPermits); // 可以消费的最大令牌数
-
double freshPermits = requiredPermits - storedPermitsToSpend; // 还需要的令牌数(若需要的大于已有的令牌,则下次请求需要延时等待;否则此值为0,即不需要等待)
-
long waitMicros =
-
storedPermitsToWaitTime(this.storedPermits, storedPermitsToSpend)
-
+ (long) (freshPermits * stableIntervalMicros); // SmoothBursty为0(SmoothWarmingUp具体计算)+需要等待时间
-
-
this.nextFreeTicketMicros = (nextFreeTicketMicros, waitMicros); // 计算此次用了这么多令牌后,下次需要等待到什么时候
-
this.storedPermits -= storedPermitsToSpend;//减少消耗掉的令牌
-
return returnValue;
-
}
4. 对于延迟,RateLimiter使用StopWatch实现不可中断挂起
-
public boolean tryAcquire(int permits, long timeout, TimeUnit unit) {
-
long timeoutMicros = ((timeout), 0L);
-
checkPermits(permits);
-
long microsToWait;
-
synchronized(this.mutex()) {
-
long nowMicros = this.();
-
if (!this.canAcquire(nowMicros, timeoutMicros)) {
-
return false;
-
}
-
-
microsToWait = this.reserveAndGetWaitLength(permits, nowMicros);
-
}
-
-
this.(microsToWait);//根据计算出来的时间不可中断挂起
-
return true;
-
}
5. RateLimiter由SmoothRateLimiter继承,其中会根据rate计算maxPermits和stableIntervalMicros,并且其有SmoothBursty和SmoothWarmingUp两种方式