RateLimit-使用guava來做接口限流代碼示例
本文主要研究的是RateLimit-使用guava來做接口限流的相關(guān)內(nèi)容,具體如下。
一、問題描述
某天A君突然發(fā)現(xiàn)自己的接口請(qǐng)求量突然漲到之前的10倍,沒多久該接口幾乎不可使用,并引發(fā)連鎖反應(yīng)導(dǎo)致整個(gè)系統(tǒng)崩潰。如何應(yīng)對(duì)這種情況呢?生活給了我們答案:比如老式電閘都安裝了保險(xiǎn)絲,一旦有人使用超大功率的設(shè)備,保險(xiǎn)絲就會(huì)燒斷以保護(hù)各個(gè)電器不被強(qiáng)電流給燒壞。同理我們的接口也需要安裝上“保險(xiǎn)絲”,以防止非預(yù)期的請(qǐng)求對(duì)系統(tǒng)壓力過大而引起的系統(tǒng)癱瘓,當(dāng)流量過大時(shí),可以采取拒絕或者引流等機(jī)制。
二、常用的限流算法
常用的限流算法有兩種:漏桶算法和令牌桶算法。
漏桶算法思路很簡(jiǎn)單,請(qǐng)求先進(jìn)入到漏桶里,漏桶以一定的速度出水,當(dāng)水請(qǐng)求過大會(huì)直接溢出,可以看出漏桶算法能強(qiáng)行限制數(shù)據(jù)的傳輸速率。
圖1 漏桶算法示意圖
對(duì)于很多應(yīng)用場(chǎng)景來說,除了要求能夠限制數(shù)據(jù)的平均傳輸速率外,還要求允許某種程度的突發(fā)傳輸。這時(shí)候漏桶算法可能就不合適了,令牌桶算法更為適合。如圖2所示,令牌桶算法的原理是系統(tǒng)會(huì)以一個(gè)恒定的速度往桶里放入令牌,而如果請(qǐng)求需要被處理,則需要先從桶里獲取一個(gè)令牌,當(dāng)桶里沒有令牌可取時(shí),則拒絕服務(wù)。
圖2 令牌桶算法示意圖
三、限流工具類RateLimiter
google開源工具包guava提供了限流工具類RateLimiter,該類基于“令牌桶算法”,非常方便使用。該類的接口具體的使用請(qǐng)參考:RateLimiter使用實(shí)踐。
RateLimiter 使用Demo
package ratelimite; import com.google.common.util.concurrent.RateLimiter; public class RateLimiterDemo { public static void main(String[] args) { testNoRateLimiter(); testWithRateLimiter(); } public static void testNoRateLimiter() { long start = System.currentTimeMillis(); for (int i = 0; i < 10; i++) { System.out.println("call execute.." + i); } long end = System.currentTimeMillis(); System.out.println(end - start); } public static void testWithRateLimiter() { long start = System.currentTimeMillis(); RateLimiter limiter = RateLimiter.create(10.0); // 每秒不超過10個(gè)任務(wù)被提交 for (int i = 0; i < 10; i++) { limiter.acquire(); // 請(qǐng)求RateLimiter, 超過permits會(huì)被阻塞 System.out.println("call execute.." + i); } long end = System.currentTimeMillis(); System.out.println(end - start); } }
四 Guava并發(fā):ListenableFuture與RateLimiter示例
概念
ListenableFuture顧名思義就是可以監(jiān)聽的Future,它是對(duì)java原生Future的擴(kuò)展增強(qiáng)。我們知道Future表示一個(gè)異步計(jì)算任務(wù),當(dāng)任務(wù)完成時(shí)可以得到計(jì)算結(jié)果。如果我們希望一旦計(jì)算完成就拿到結(jié)果展示給用戶或者做另外的計(jì)算,就必須使用另一個(gè)線程不斷的查詢計(jì)算狀態(tài)。這樣做,代碼復(fù)雜,而且效率低下。使用ListenableFuture Guava幫我們檢測(cè)Future是否完成了,如果完成就自動(dòng)調(diào)用回調(diào)函數(shù),這樣可以減少并發(fā)程序的復(fù)雜度。
推薦使用第二種方法,因?yàn)榈诙N方法可以直接得到Future的返回值,或者處理錯(cuò)誤情況。本質(zhì)上第二種方法是通過調(diào)動(dòng)第一種方法實(shí)現(xiàn)的,做了進(jìn)一步的封裝。
另外ListenableFuture還有其他幾種內(nèi)置實(shí)現(xiàn):
SettableFuture:不需要實(shí)現(xiàn)一個(gè)方法來計(jì)算返回值,而只需要返回一個(gè)固定值來做為返回值,可以通過程序設(shè)置此Future的返回值或者異常信息
CheckedFuture: 這是一個(gè)繼承自ListenableFuture接口,他提供了checkedGet()方法,此方法在Future執(zhí)行發(fā)生異常時(shí),可以拋出指定類型的異常。
RateLimiter類似于JDK的信號(hào)量Semphore,他用來限制對(duì)資源并發(fā)訪問的線程數(shù),本文介紹RateLimiter使用
代碼示例
import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.RateLimiter; public class ListenableFutureDemo { public static void main(String[] args) { testRateLimiter(); testListenableFuture(); } /** * RateLimiter類似于JDK的信號(hào)量Semphore,他用來限制對(duì)資源并發(fā)訪問的線程數(shù) */ public static void testRateLimiter() { ListeningExecutorService executorService = MoreExecutors .listeningDecorator(Executors.newCachedThreadPool()); RateLimiter limiter = RateLimiter.create(5.0); // 每秒不超過4個(gè)任務(wù)被提交 for (int i = 0; i < 10; i++) { limiter.acquire(); // 請(qǐng)求RateLimiter, 超過permits會(huì)被阻塞 final ListenableFuture<Integer> listenableFuture = executorService .submit(new Task("is "+ i)); } } public static void testListenableFuture() { ListeningExecutorService executorService = MoreExecutors .listeningDecorator(Executors.newCachedThreadPool()); final ListenableFuture<Integer> listenableFuture = executorService .submit(new Task("testListenableFuture")); //同步獲取調(diào)用結(jié)果 try { System.out.println(listenableFuture.get()); } catch (InterruptedException e1) { e1.printStackTrace(); } catch (ExecutionException e1) { e1.printStackTrace(); } //第一種方式 listenableFuture.addListener(new Runnable() { @Override public void run() { try { System.out.println("get listenable future's result " + listenableFuture.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } } , executorService); //第二種方式 Futures.addCallback(listenableFuture, new FutureCallback<Integer>() { @Override public void onSuccess(Integer result) { System.out .println("get listenable future's result with callback " + result); } @Override public void onFailure(Throwable t) { t.printStackTrace(); } } ); } } class Task implements Callable<Integer> { String str; public Task(String str){ this.str = str; } @Override public Integer call() throws Exception { System.out.println("call execute.." + str); TimeUnit.SECONDS.sleep(1); return 7; } }
Guava版本
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>14.0.1</version> </dependency>
總結(jié)
以上就是本文關(guān)于RateLimit-使用guava來做接口限流代碼示例的全部?jī)?nèi)容,希望對(duì)大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)專題,如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持!
- Java基于Guava Retrying實(shí)現(xiàn)重試功能
- Springboot整合GuavaCache緩存過程解析
- Java內(nèi)存緩存工具Guava LoadingCache使用解析
- SpringBoot加入Guava Cache實(shí)現(xiàn)本地緩存代碼實(shí)例
- 詳解Guava Cache本地緩存在Spring Boot應(yīng)用中的實(shí)踐
- springboot使用GuavaCache做簡(jiǎn)單緩存處理的方法
- Java編程guava RateLimiter實(shí)例解析
- Guava - 并行編程Futures詳解
- Java Guava排序器Ordering原理及代碼實(shí)例
相關(guān)文章
詳解Java編譯優(yōu)化之循環(huán)展開和粗化鎖
之前在講JIT的時(shí)候,有提到在編譯過程中的兩種優(yōu)化循環(huán)展開和粗化鎖,今天從Assembly的角度來驗(yàn)證一下這兩種編譯優(yōu)化方法,快來看看吧。2021-06-06java集合類arraylist循環(huán)中刪除特定元素的方法
下面小編就為大家?guī)硪黄狫ava集合類ArrayList循環(huán)中刪除特定元素的方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-11-11struts2+jsp+jquery+Jcrop實(shí)現(xiàn)圖片裁剪并上傳實(shí)例
本篇文章主要介紹了struts2+jsp+jquery+Jcrop實(shí)現(xiàn)圖片裁剪并上傳實(shí)例,具有一定的參考價(jià)值,有興趣的可以了解一下。2017-01-01SpringMVC之DispatcherServlet配置文件應(yīng)該放在哪里呢
這篇文章主要介紹了SpringMVC之DispatcherServlet配置文件應(yīng)該放在哪里的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11Spring Boot實(shí)現(xiàn)對(duì)文件進(jìn)行壓縮下載功能
在Web應(yīng)用中,文件下載功能是一個(gè)常見的需求,特別是當(dāng)你需要提供用戶下載各種類型的文件時(shí),本文將演示如何使用Spring Boot框架來實(shí)現(xiàn)一個(gè)簡(jiǎn)單而強(qiáng)大的文件下載功能,需要的朋友跟隨小編一起學(xué)習(xí)吧2023-09-09java中request對(duì)象各種方法的使用實(shí)例分析
這篇文章主要介紹了java中request對(duì)象各種方法的使用,結(jié)合完整實(shí)例形式較為詳細(xì)的分析了request對(duì)象的功能及其常用方法的使用技巧,需要的朋友可以參考下2015-12-12有關(guān)Java常見的誤解小結(jié)(來看一看)
下面小編就為大家?guī)硪黄嘘P(guān)Java常見的誤解小結(jié)(來看一看)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-05-05Spring Boot Feign服務(wù)調(diào)用之間帶token問題
這篇文章主要介紹了Spring Boot Feign服務(wù)調(diào)用之間帶token的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09