一 RateLimiter介紹
RateLimiter是guava提供的基於令牌桶算法的實現類,可以非常簡單高效的完成限流。
所以需要引入guava包
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>25.1-jre</version>
</dependency>
guava的RateLimiter使用的是令牌桶算法,也就是以固定的頻率向桶中放入令牌,例如一秒鍾10枚令牌,實際業務在每次響應請求之前都從桶中獲取令牌,只有取到令牌的請求才會被成功響應,獲取的方式有兩種:阻塞等待令牌或者取不到立即返回失敗

二 使用舉例:
/**
* Created by wuwf on 17/7/11.
* 有很多個任務,但希望每秒不超過X個,可用此類
*/
public class Demo1 {
public static void main(String[] args) {
//0.5代表一秒最多多少個
RateLimiter rateLimiter = RateLimiter.create(0.5);
List<Runnable> tasks = new ArrayList<Runnable>();
for (int i = 0; i < 10; i++) {
tasks.add(new UserRequest(i));
}
ExecutorService threadPool = Executors.newCachedThreadPool();
for (Runnable runnable : tasks) {
System.out.println("等待時間:" + rateLimiter.acquire());
threadPool.execute(runnable);
}
}
private static class UserRequest implements Runnable {
private int id;
public UserRequest(int id) {
this.id = id;
}
public void run() {
System.out.println(id);
}
}
}

三 常見限流實現方式
目前常見的共四種方式
1通過限制單位時間段內調用量來限流
通過限制某個服務的單位時間內的調用量來進行限流。我們需要做的就是通過一個計數器統計單位時間段某個服務的訪問量,如果超過了我們設定的閾值,
則該單位時間段內則不允許繼續訪問,或者把接下來的請求放入隊列中等待到下一個單位時間段繼續訪問。
- 優點:實現簡單,閾值可動態配置。
- 缺點:若單位時間內前一小段時間內就被大流量消耗完,則將導致該時間段內剩余的時間都拒絕服務。該現象為:“突刺消耗”。
2通過限制系統的並發調用程度來限流
通過並發限制來限流,我們通過嚴格限制某服務的並發訪問程度,其實也就限制了該服務單位時間段內的訪問量,
比如限制服務的並發訪問數是100,而服務處理的平均耗時是10毫秒,該服務每秒能提供( 1000 / 10 ) * 100 = 10,000 次。
- 優點:有更嚴格的限制邊界,適合連接數、線程數的一個限制。
- 缺點:對服務來說,並發閾值調優困難,難以准確判定服務閾值設置多少合適。一般采用Semaphore實現,但Semaphore沒有提供重設信號量的方法,所以閾值動態配置也是問題。
3漏桶算法
請求流量以不確定速率申請資源,程序處理以恆定的速率進行,就是漏桶算法的基本原理。
漏斗有一個進水口 和 一個出水口,出水口以一定速率出水,並且有一個最大出水速率:
- 在漏斗中沒有水的時候
- 如果進水速率小於等於最大出水速率,那么,出水速率等於進水速率,此時,不會積水
- 如果進水速率大於最大出水速率,那么,漏斗以最大速率出水,此時,多余的水會積在漏斗中
- 在漏斗中有水的時候
- 出水口以最大速率出水
- 如果漏斗未滿,且有進水的話,那么這些水會積在漏斗中
如果漏斗已滿,且有進水的話,那么這些水會溢出到漏斗之外。
- 優點:不管突然流量有多大,漏桶都保證了流量的常速率輸出。
- 缺點:漏桶的出水速度是恆定的,那么意味着如果瞬時大流量的話,將有大部分請求被丟棄掉。
4令牌桶算法
對於很多應用場景來說,除了要求能夠限制數據的平均傳輸速率外,還要求允許某種程度的突發傳輸。這時候漏桶算法可能就不合適了,令牌桶算法更為適合。
令牌桶算法的原理是系統以恆定的速率產生令牌,然后把令牌放到令牌桶中,令牌桶有一個容量,當令牌桶滿了的時候,再向其中放令牌,
那么多余的令牌會被丟棄;當想要處理一個請求的時候,需要從令牌桶中取出一個令牌,如果此時令牌桶中沒有令牌,那么則拒絕該請求。

- 優點:令牌桶算法能夠在限制調用的平均速率的同時還允許某種程度的突發調用。guava RateLimiter就是基於令牌桶算法實現,所以代碼實現簡易。可動態配置令牌生成速率。
- 缺點:
基於以上四種算法的介紹,令牌桶不僅能夠限制調用的平均速率同時還允許一定程度的突發調用,不會導致突發調用大量請求被丟棄,更加靈活,且代碼實現簡易。綜上:建議選擇令牌桶算法實現限流。
