一晒夹、概要說明
最近在工作中涉及到類似搶購的業(yè)務(wù)惕味,在請求并發(fā)量高的時候會阻塞到正常業(yè)務(wù)的訪問。因此考慮使用guawa的rateLimiter進行限流矿咕,對超限的流量進行降級處理。保證正常的業(yè)務(wù)運行
二、RateLimiter的特性
RateLimiter使用令牌桶算法碳柱,相對于傳統(tǒng)的根據(jù)每秒的請求數(shù)進行限流的方式捡絮,令牌桶算法會讓流量更加平滑地流入。eg.QPS限制為100莲镣,假如這100個請求是在1ms內(nèi)同時進來福稳,也有可能讓系統(tǒng)崩潰。
三瑞侮、核心源碼分析
/**
* 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;
}
我們重點關(guān)注reserveEarliestAvailable這個方法的圆。
storedPermits為令牌生成的數(shù)量,resync這個方法會根據(jù)當(dāng)前的時間和上一次生成的令牌的時間對比半火,計算出本次生成的令牌數(shù)量越妈。eg.QPS設(shè)置為100,上一次請求和當(dāng)前時間相隔為2ms钮糖,則當(dāng)前的令牌數(shù)量為20梅掠。