通用限流方案:漏桶算法和令牌桶算法
漏桶算法
一定容量的桶存储上游的请求,以一定的速度出水,水流速度过大直接溢出。限制数据的传输速度。
令牌桶算法
除了控制流量的速度外,容忍突发暴增的传输,以稳定速度放置令牌;如果请求需要被处理,先从桶中取出令牌,如果没有令牌,拒绝服务。
Grava令牌桶限流算法的核心实现
/**
* @param permits 令牌桶的数量
* @param timeout 等待许可证的最长时间。负值被视为零。
* @param unit 超时参数的时间单位
**/
public boolean tryAcquire(int permits, long timeout, TimeUnit unit) {
long timeoutMicros = Math.max(unit.toMicros(timeout), 0L);
checkPermits(permits);
long microsToWait;
synchronized(this.mutex()) {
long nowMicros = this.stopwatch.readMicros();
if (!this.canAcquire(nowMicros, timeoutMicros)) {
return false;
}
microsToWait = this.reserveAndGetWaitLength(permits, nowMicros);
}
this.stopwatch.sleepMicrosUninterruptibly(microsToWait);
return true;
}
private boolean canAcquire(long nowMicros, long timeoutMicros) {
return this.queryEarliestAvailable(nowMicros) - timeoutMicros <= nowMicros;
}
/**
* Reserves next ticket and returns the wait time that the caller must wait for.
* 保留下一张票并返回呼叫者必须等待的等待时间。
**/
final long reserveEarliestAvailable(int requiredPermits, long nowMicros) {
this.resync(nowMicros); //基于当前时间更新{@code storedPermits}和{@code nextFreeTicketMicros}
long returnValue = this.nextFreeTicketMicros;
double storedPermitsToSpend = Math.min((double)requiredPermits, this.storedPermits);
double freshPermits = (double)requiredPermits - storedPermitsToSpend;
long waitMicros = this.storedPermitsToWaitTime(this.storedPermits, storedPermitsToSpend) + (long)(freshPermits * this.stableIntervalMicros);
this.nextFreeTicketMicros = LongMath.saturatedAdd(this.nextFreeTicketMicros, waitMicros);
this.storedPermits -= storedPermitsToSpend;
return returnValue;
}