1. 程式人生 > >Guava官方文件-RateLimiter類

Guava官方文件-RateLimiter類

原文連結 作者:Dimitris Andreou  譯者:魏嘉鵬 校對:方騰飛token_bucket

RateLimiter 從概念上來講,速率限制器會在可配置的速率下分配許可證。如果必要的話,每個acquire() 會阻塞當前執行緒直到許可證可用後獲取該許可證。一旦獲取到許可證,不需要再釋放許可證。

校對注:RateLimiter使用的是一種叫令牌桶的流控演算法,RateLimiter會按照一定的頻率往桶裡扔令牌,執行緒拿到令牌才能執行,比如你希望自己的應用程式QPS不要超過1000,那麼RateLimiter設定1000的速率後,就會每秒往桶裡扔1000個令牌。

com.google.common.util.concurrent.RateLimiter

@ThreadSafe
@Betapublic
abstract class RateLimiter extends Object


RateLimiter經常用於限制對一些物理資源或者邏輯資源的訪問速率。與Semaphore 相比,Semaphore 限制了併發訪問的數量而不是使用速率。(注意儘管併發性和速率是緊密相關的,比如參考Little定律

通過設定許可證的速率來定義RateLimiter。在預設配置下,許可證會在固定的速率下被分配,速率單位是每秒多少個許可證。為了確保維護配置的速率,許可會被平穩地分配,許可之間的延遲會做調整。
可能存在配置一個擁有預熱期的RateLimiter 的情況,在這段時間內,每秒分配的許可數會穩定地增長直到達到穩定的速率。

舉例來說明如何使用RateLimiter,想象下我們需要處理一個任務列表,但我們不希望每秒的任務提交超過兩個:

//速率是每秒兩個許可
final RateLimiter rateLimiter = RateLimiter.create(2.0);

void submitTasks(List tasks, Executor executor) {
    for (Runnable task : tasks) {
        rateLimiter.acquire(); // 也許需要等待
        executor.execute(task);
    }
}

再舉另外一個例子,想象下我們製造了一個數據流,並希望以每秒5kb的速率處理它。可以通過要求每個位元組代表一個許可,然後指定每秒5000個許可來完成:

// 每秒5000個許可
final RateLimiter rateLimiter = RateLimiter.create(5000.0); 

void submitPacket(byte[] packet) {
    rateLimiter.acquire(packet.length);
    networkService.send(packet);
}

有一點很重要,那就是請求的許可數從來不會影響到請求本身的限制(呼叫acquire(1) 和呼叫acquire(1000) 將得到相同的限制效果,如果存在這樣的呼叫的話),但會影響下一次請求的限制,也就是說,如果一個高開銷的任務抵達一個空閒的RateLimiter,它會被馬上許可,但是下一個請求會經歷額外的限制,從而來償付高開銷任務。注意:RateLimiter 並不提供公平性的保證。

Since:13.0  作者:   Dimitris Andreou

方法摘要

修飾符和型別 方法和描述
double acquire()
從RateLimiter獲取一個許可,該方法會被阻塞直到獲取到請求
double acquire(int permits)
從RateLimiter獲取指定許可數,該方法會被阻塞直到獲取到請求
static RateLimiter create(double permitsPerSecond)
根據指定的穩定吞吐率建立RateLimiter,這裡的吞吐率是指每秒多少許可數(通常是指QPS,每秒多少查詢)
static RateLimiter create(double permitsPerSecond, long warmupPeriod, TimeUnit unit)
根據指定的穩定吞吐率和預熱期來建立RateLimiter,這裡的吞吐率是指每秒多少許可數(通常是指QPS,每秒多少個請求量),在這段預熱時間內,RateLimiter每秒分配的許可數會平穩地增長直到預熱期結束時達到其最大速率。(只要存在足夠請求數來使其飽和)
double getRate()
返回RateLimiter 配置中的穩定速率,該速率單位是每秒多少許可數
void setRate(double permitsPerSecond)
更新RateLimite的穩定速率,引數permitsPerSecond 由構造RateLimiter的工廠方法提供。
String toString()
返回物件的字元表現形式
boolean tryAcquire()
從RateLimiter 獲取許可,如果該許可可以在無延遲下的情況下立即獲取得到的話
boolean tryAcquire(int permits)
從RateLimiter 獲取許可數,如果該許可數可以在無延遲下的情況下立即獲取得到的話
boolean tryAcquire(int permits, long timeout, TimeUnit unit)
從RateLimiter 獲取指定許可數如果該許可數可以在不超過timeout的時間內獲取得到的話,或者如果無法在timeout 過期之前獲取得到許可數的話,那麼立即返回false (無需等待)
boolean tryAcquire(long timeout, TimeUnit unit)
從RateLimiter 獲取許可如果該許可可以在不超過timeout的時間內獲取得到的話,或者如果無法在timeout 過期之前獲取得到許可的話,那麼立即返回false(無需等待)
從java.lang.Object 類繼承的方法
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait

方法細節

create
public static RateLimiter create(double permitsPerSecond)
根據指定的穩定吞吐率建立RateLimiter,這裡的吞吐率是指每秒多少許可數(通常是指QPS,每秒多少查詢)。
The returned RateLimiter ensures that on average no more than permitsPerSecond are issued during any given second, with sustained requests being smoothly spread over each second. When the incoming request rate exceeds permitsPerSecond the rate limiter will release one permit every (1.0 / permitsPerSecond) seconds. When the rate limiter is unused, bursts of up to permitsPerSecond permits will be allowed, with subsequent requests being smoothly limited at the stable rate of permitsPerSecond.
返回的RateLimiter 確保了在平均情況下,每秒釋出的許可數不會超過permitsPerSecond,每秒鐘會持續傳送請求。當傳入請求速率超過permitsPerSecond,速率限制器會每秒釋放一個許可(1.0 / permitsPerSecond 這裡是指設定了permitsPerSecond為1.0) 。當速率限制器閒置時,允許許可數暴增到permitsPerSecond,隨後的請求會被平滑地限制在穩定速率permitsPerSecond中。
引數:
permitsPerSecond – 返回的RateLimiter的速率,意味著每秒有多少個許可變成有效。
丟擲:
IllegalArgumentException – 如果permitsPerSecond為負數或者為0
create
public static RateLimiter create(double permitsPerSecond,long warmupPeriod,TimeUnit unit)
根據指定的穩定吞吐率和預熱期來建立RateLimiter,這裡的吞吐率是指每秒多少許可數(通常是指QPS,每秒多少查詢),在這段預熱時間內,RateLimiter每秒分配的許可數會平穩地增長直到預熱期結束時達到其最大速率(只要存在足夠請求數來使其飽和)。同樣地,如果RateLimiter 在warmupPeriod時間內閒置不用,它將會逐步地返回冷卻狀態。也就是說,它會像它第一次被建立般經歷同樣的預熱期。返回的RateLimiter 主要用於那些需要預熱期的資源,這些資源實際上滿足了請求(比如一個遠端服務),而不是在穩定(最大)的速率下可以立即被訪問的資源。返回的RateLimiter 在冷卻狀態下啟動(即預熱期將會緊跟著發生),並且如果被長期閒置不用,它將回到冷卻狀態。
引數:
  • permitsPerSecond – 返回的RateLimiter的速率,意味著每秒有多少個許可變成有效。
  • warmupPeriod – 在這段時間內RateLimiter會增加它的速率,在抵達它的穩定速率或者最大速率之前
  • unit – 引數warmupPeriod 的時間單位

丟擲:

  • IllegalArgumentException – 如果permitsPerSecond為負數或者為0
setRate
public final void setRate(double permitsPerSecond)
更新RateLimite的穩定速率,引數permitsPerSecond 由構造RateLimiter的工廠方法提供。呼叫該方法後,當前限制執行緒不會被喚醒,因此他們不會注意到最新的速率;只有接下來的請求才會。需要注意的是,由於每次請求償還了(通過等待,如果需要的話)上一次請求的開銷,這意味著緊緊跟著的下一個請求不會被最新的速率影響到,在呼叫了setRate 之後;它會償還上一次請求的開銷,這個開銷依賴於之前的速率。RateLimiter的行為在任何方式下都不會被改變,比如如果 RateLimiter 有20秒的預熱期配置,在此方法被呼叫後它還是會進行20秒的預熱。
引數:
permitsPerSecond – RateLimiter的新的穩定速率
丟擲:
IllegalArgumentException – 如果permitsPerSecond為負數或者為0
getRate
public final double getRate()
返回RateLimiter 配置中的穩定速率,該速率單位是每秒多少許可數。它的初始值相當於構造這個RateLimiter的工廠方法中的引數permitsPerSecond ,並且只有在呼叫setRate(double)後才會被更新。
acquire
public double acquire()
從RateLimiter獲取一個許可,該方法會被阻塞直到獲取到請求。如果存在等待的情況的話,告訴呼叫者獲取到該請求所需要的睡眠時間。該方法等同於acquire(1)。
返回:
time spent sleeping to enforce rate, in seconds; 0.0 if not rate-limited
執行速率的所需要的睡眠時間,單位為妙;如果沒有則返回0
Since:
16.0 (版本13.0沒有返回值)
acquire
public double acquire(int permits)
從RateLimiter獲取指定許可數,該方法會被阻塞直到獲取到請求數。如果存在等待的情況的話,告訴呼叫者獲取到這些請求數所需要的睡眠時間。
引數:
permits – 需要獲取的許可數
返回:
執行速率的所需要的睡眠時間,單位為妙;如果沒有則返回0
丟擲:
IllegalArgumentException – 如果請求的許可數為負數或者為0
Since:
16.0 (版本13.0沒有返回值)
tryAcquire
public boolean tryAcquire(long timeout,TimeUnit unit)
從RateLimiter獲取許可如果該許可可以在不超過timeout的時間內獲取得到的話,或者如果無法在timeout 過期之前獲取得到許可的話,那麼立即返回false(無需等待)。該方法等同於tryAcquire(1, timeout, unit)。
引數:
  • timeout – 等待許可的最大時間,負數以0處理
  • unit – 引數timeout 的時間單位

返回:
true表示獲取到許可,反之則是false
丟擲:
IllegalArgumentException – 如果請求的許可數為負數或者為0

tryAcquire
public boolean tryAcquire(int permits)
從RateLimiter 獲取許可數,如果該許可數可以在無延遲下的情況下立即獲取得到的話。該方法等同於tryAcquire(permits, 0, anyUnit)。
引數:
permits – 需要獲取的許可數
返回:
true表示獲取到許可,反之則是false
丟擲:
IllegalArgumentException – 如果請求的許可數為負數或者為0
Since:
14.0
tryAcquire
public boolean tryAcquire()
從RateLimiter 獲取許可,如果該許可可以在無延遲下的情況下立即獲取得到的話。
該方法等同於tryAcquire(1)。
返回:
true表示獲取到許可,反之則是false
Since:
14.0
tryAcquire
public boolean tryAcquire(int permits,long timeout,TimeUnit unit)
從RateLimiter 獲取指定許可數如果該許可數可以在不超過timeout的時間內獲取得到的話,或者如果無法在timeout 過期之前獲取得到許可數的話,那麼立即返回false (無需等待)。
引數:
permits – 需要獲取的許可數
timeout – 等待許可數的最大時間,負數以0處理
unit – 引數timeout 的時間單位
返回:
true表示獲取到許可,反之則是false
丟擲:
IllegalArgumentException -如果請求的許可數為負數或者為0
toString
public String toString()
以下描述複製於java.lang.Object類。
返回物件的字元表現形式。通常來講,toString 方法返回一個“文字化呈現”物件的字串。
結果應該是一個簡明但易於讀懂的資訊表示式。建議所有子類都重寫該方法。
toString 方法返回一個由例項的類名,字元’@’和以無符號十六進位制表示的物件的雜湊值組成的字串。換句話說,該方法返回的字串等同於:
getClass().getName() + ‘@’ + Integer.toHexString(hashCode())
過載:
Object類的toString方法
返回:
物件的字元表現形式