一、概要说明
最近在工作中涉及到类似抢购的业务,在请求并发量高的时候会阻塞到正常业务的访问。因此考虑使用guawa的rateLimiter进行限流,对超限的流量进行降级处理。保证正常的业务运行
二、RateLimiter的特性
RateLimiter使用令牌桶算法,相对于传统的根据每秒的请求数进行限流的方式,令牌桶算法会让流量更加平滑地流入。eg.QPS限制为100,假如这100个请求是在1ms内同时进来,也有可能让系统崩溃。
三、核心源码分析
/**
* Acquires the given number of permits from this {@code RateLimiter}, blocking until the request
* can be granted. Tells the amount of time slept, if any.
*
* @param permits the number of permits to acquire
* @return time spent sleeping to enforce rate, in seconds; 0.0 if not rate-limited
* @throws IllegalArgumentException if the requested number of permits is negative or zero
* @since 16.0 (present in 13.0 with {@code void} return type})
*/
@CanIgnoreReturnValue
public double acquire(int permits) {
long microsToWait = reserve(permits);
stopwatch.sleepMicrosUninterruptibly(microsToWait);
return 1.0 * microsToWait / SECONDS.toMicros(1L);
}
/**
* Reserves the given number of permits from this {@code RateLimiter} for future use, returning
* the number of microseconds until the reservation can be consumed.
*
* @return time in microseconds to wait until the resource can be acquired, never negative
*/
final long reserve(int permits) {
checkPermits(permits);
synchronized (mutex()) {
return reserveAndGetWaitLength(permits, stopwatch.readMicros());
}
}
/**
* Reserves next ticket and returns the wait time that the caller must wait for.
*
* @return the required wait time, never negative
*/
final long reserveAndGetWaitLength(int permits, long nowMicros) {
long momentAvailable = reserveEarliestAvailable(permits, nowMicros);
return max(momentAvailable - nowMicros, 0);
}
@Override
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);
this.nextFreeTicketMicros = LongMath.saturatedAdd(nextFreeTicketMicros, waitMicros);
this.storedPermits -= storedPermitsToSpend;
return returnValue;
}
我们重点关注reserveEarliestAvailable这个方法。
storedPermits为令牌生成的数量,resync这个方法会根据当前的时间和上一次生成的令牌的时间对比,计算出本次生成的令牌数量。eg.QPS设置为100,上一次请求和当前时间相隔为2ms,则当前的令牌数量为20。
网友评论