RateLimiter
算法原理
RateLimiter 从概念上来讲,速率限制器会在可配置的速率下分配许可证。如果必要的话,每个acquire() 会阻塞当前线程直到许可证可用后获取该许可证。一旦获取到许可证,不需要再释放许可证。
使用案例
- RateLimiter.create(10);
- RateLimiter.acquire();
有两个实现子类
SmoothBursty
- acquire后立即开始
SmoothWarmingUp
- 有一段warm up间隔,后再开始
源码解析(SmoothBursty)
创建令牌桶
* RateLimiter.create(permitsPerSecond);
* permitsPerSecond : 每一秒发放的令牌数
核心参数
maxBurstSeconds
- 统计的时间范围,默认为1,即每一秒内发放的令牌
nextFreeTicketMicros
- 下一个令牌可以获取的时间点,单位微秒
storedPermits
- 已有的令牌数
maxPermits
最大的令牌数
maxPermits = permitsPerSecond * maxBurstSeconds
stableIntervalMicros
令牌之间的平均间隔时间,单位微秒
stableIntervalMicros = 1秒 / permitsPerSecond
源码分析
public static RateLimiter create(double permitsPerSecond) {
return create(SleepingStopwatch.createFromSystemTimer(), permitsPerSecond);
}
static RateLimiter create(SleepingStopwatch stopwatch, double permitsPerSecond) {
//设置时间范围长度
RateLimiter rateLimiter = new SmoothBursty(stopwatch, 1.0 /* maxBurstSeconds */);
rateLimiter.setRate(permitsPerSecond);
return rateLimiter;
}
public final void setRate(double permitsPerSecond) {
checkArgument(
permitsPerSecond > 0.0 && !Double.isNaN(permitsPerSecond), "rate must be positive");
//互斥锁
synchronized (mutex()) {
//设置令牌桶频率
doSetRate(permitsPerSecond, stopwatch.readMicros());
}
}
final void doSetRate(double permitsPerSecond, long nowMicros) {
//更新参数
resync(nowMicros);
//令牌平均间隔时间
double stableIntervalMicros = SECONDS.toMicros(1L) / permitsPerSecond;
this.stableIntervalMicros = stableIntervalMicros;
doSetRate(permitsPerSecond, stableIntervalMicros);
}
void doSetRate(double permitsPerSecond, double stableIntervalMicros) {
double oldMaxPermits = this.maxPermits;
//最大令牌数
maxPermits = maxBurstSeconds * permitsPerSecond;
//设置令牌桶的已有令牌数,初始状态时为0
if (oldMaxPermits == Double.POSITIVE_INFINITY) {
// if we don't special-case this, we would get storedPermits == NaN, below
storedPermits = maxPermits;
} else {
storedPermits = (oldMaxPermits == 0.0)
? 0.0 // initial state
: storedPermits * maxPermits / oldMaxPermits;
}
}
//更新参数,入参为当前时间
void resync(long nowMicros) {
// 如果当前时间超过下一个令牌可获取时间,更新参数,并且将下个令牌的可获取时间更新为当前时间
if (nowMicros > nextFreeTicketMicros) {
//更新令牌桶里存储的令牌数,包括 nowMicros - nextFreeTicketMicros 时间范围内补充的令牌数
storedPermits = min(maxPermits,
storedPermits
+ (nowMicros - nextFreeTicketMicros) / coolDownIntervalMicros());
nextFreeTicketMicros = nowMicros;
}
}
获取令牌
rateLimiter.acquire(int permits)
- permits : 需要获取的令牌数
源码分析
//获取令牌
public double acquire(int permits) {
long microsToWait = reserve(permits);
stopwatch.sleepMicrosUninterruptibly(microsToWait);
return 1.0 * microsToWait / SECONDS.toMicros(1L);
}
final long reserve(int permits) {
checkPermits(permits);
synchronized (mutex()) {
return reserveAndGetWaitLength(permits, stopwatch.readMicros());
}
}
//获取令牌,并返回需要等待的时间,单位微秒
final long reserveAndGetWaitLength(int permits, long nowMicros) {
long momentAvailable = reserveEarliestAvailable(permits, nowMicros);
return max(momentAvailable - nowMicros, 0);
}
//获取最近的一个可用令牌的时间
final long reserveEarliestAvailable(int requiredPermits, long nowMicros) {
//更新参数
resync(nowMicros);
//记录最近一个可用令牌的时间
long returnValue = nextFreeTicketMicros;
//将要花费的令牌数
double storedPermitsToSpend = min(requiredPermits, this.storedPermits);
//未花费掉的令牌数
double freshPermits = requiredPermits - storedPermitsToSpend;
//需要等待的时间,未花费的令牌数*令牌间隔时间
long waitMicros = storedPermitsToWaitTime(this.storedPermits, storedPermitsToSpend)
+ (long) (freshPermits * stableIntervalMicros);
try {
//更新下个可用令牌的可获取时间,最近可用令牌的时间+需要等待的时间
this.nextFreeTicketMicros = LongMath.checkedAdd(nextFreeTicketMicros, waitMicros);
} catch (ArithmeticException e) {
this.nextFreeTicketMicros = Long.MAX_VALUE;
}
//更新令牌桶里的令牌数
this.storedPermits -= storedPermitsToSpend;
return returnValue;
}
long storedPermitsToWaitTime(double storedPermits, double permitsToTake) {
return 0L;
}