最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于Java編寫(xiě)一個(gè)限流工具類RateLimiter

 更新時(shí)間:2024年01月26日 17:10:37   作者:不歸SUN  
這篇文章主要為大家詳細(xì)介紹了如何基于Java編寫(xiě)一個(gè)限流工具類RateLimiter,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

限流工具類RateLimiter

原理:令牌桶算法

有一個(gè)桶,桶的容量固定。系統(tǒng)以恒定的速度往桶里放令牌,令牌數(shù)不超過(guò)桶的容量。

用戶發(fā)送請(qǐng)求進(jìn)來(lái),需要先從桶里獲取一個(gè)令牌才能通過(guò),獲取后桶里令牌數(shù)減一。如果系統(tǒng)兩秒一個(gè)往桶里放令牌,用戶請(qǐng)求一秒一次,那么當(dāng)令牌被取空后,操作就需要等待,會(huì)被限流。

可以應(yīng)對(duì)突發(fā)流量,當(dāng)桶里有足夠多的令牌,可以一次處理多個(gè)請(qǐng)求

1.導(dǎo)入guava依賴包

<dependency>  
    <groupId>com.google.guava</groupId>  
    <artifactId>guava</artifactId>  
    <version>30.1-jre</version>  
</dependency>

RateLimiter的集個(gè)核心方法:create()、tryAcquire()

  • acquire() 獲取一個(gè)令牌, 會(huì)阻塞當(dāng)前線程,直到獲取到一個(gè)令牌。該方法返回值類型為 double,表示當(dāng)前線程需要等待的時(shí)間(單位:秒),這個(gè)時(shí)間取決于令牌桶中令牌的剩余數(shù)量和發(fā)放速率。當(dāng)執(zhí)行 rateLimiter.acquire() 方法時(shí),如果令牌桶中還有剩余的令牌,則該方法會(huì)立即返回,返回值為 0,表示當(dāng)前線程無(wú)需等待即可獲取到一個(gè)令牌。如果令牌桶中沒(méi)有令牌,那么該方法就會(huì)阻塞當(dāng)前線程,直到令牌桶中有令牌可用或者線程被中斷。
  • acquire(int permits) 獲取指定數(shù)量的令牌, 該方法也會(huì)阻塞, 返回值為獲取到這 N 個(gè)令牌花費(fèi)的時(shí)間
  • tryAcquire() 判斷時(shí)候能獲取到令牌, 如果不能獲取立即返回 false
  • tryAcquire(int permits) 獲取指定數(shù)量的令牌, 如果不能獲取立即返回 false
  • tryAcquire(long timeout, TimeUnit unit) 判斷能否在指定時(shí)間內(nèi)獲取到令牌, 如果不能獲取立即返回 false
  • tryAcquire(int permits, long timeout, TimeUnit unit) 判斷能否在指定時(shí)間內(nèi)獲取到指定數(shù)量的令牌, 如果不能獲取立即返回 false
  • create(double permitsPerSecond) 創(chuàng)建每秒放入指定數(shù)量的令牌桶。SmoothBursty模式
  • create(5.0, 1, TimeUnit.SECONDS) 每秒5個(gè)令牌,預(yù)熱時(shí)間1秒,SmoothWarmingUp模式

2.代碼

public void limitTest(){  
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");  
  
//創(chuàng)建令牌桶,一秒一個(gè),容量為1  
RateLimiter rateLimiter = RateLimiter.create(1);  
//獲取放令牌的速率  
System.out.println("放令牌的速率:"+rateLimiter.getRate());  
for (int i=0;i<5;i++){  
//獲取令牌,會(huì)阻塞,返回等待的時(shí)間  
double acquire = rateLimiter.acquire();  
System.out.println("第"+i+" 個(gè)令牌獲取到的時(shí)間:"+LocalDateTime.now().format(dtf)+",等待時(shí)間:"+acquire);  
}  
  
//是否會(huì)立即獲取到令牌  
boolean tryAcquire = rateLimiter.tryAcquire();  
}

3.AOP+RateLimiter+注解,實(shí)現(xiàn)限流

1.創(chuàng)建注解

public @interface Limit {  
// 資源主鍵  
String key() default "";  
//最多訪問(wèn)次數(shù),代表請(qǐng)求總數(shù)量  
double permitsPerSeconds();  
// 時(shí)間:即timeout時(shí)間內(nèi),只允許有permitsPerSeconds個(gè)請(qǐng)求總數(shù)量訪問(wèn),超過(guò)的將被限制不能訪問(wèn)  
long timeout();  
//時(shí)間類型,默認(rèn)秒
TimeUnit timeUnit() default TimeUnit.SECONDS;  
  
//提示信息  
String msg() default "系統(tǒng)繁忙,請(qǐng)稍后重試";  
}

2.AOP切面

@Aspect  
@Component  
public class LimitAop {  
  
private final Map<String, RateLimiter> limitMap = Maps.newConcurrentMap();  
  
private DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");  

@Around("@annotation(com.limit.Limit)")  
public Object around(ProceedingJoinPoint joinPoint) throws Throwable{  
    MethodSignature signature = (MethodSignature) joinPoint.getSignature();  
    Method method = signature.getMethod();  
    //拿limit的注解  
    Limit limit = method.getAnnotation(Limit.class);  
    if (limit != null) {  
        // key作用:不同的接口,不同的流量控制,相當(dāng)于每個(gè)接口有一個(gè)對(duì)應(yīng)的令牌桶  
        String key = limit.key();   
        RateLimiter rateLimiter;  
        //驗(yàn)證緩存是否有命中key  
        if (!limitMap.containsKey(key)) {  
            //創(chuàng)建令牌桶  
            rateLimiter = RateLimiter.create(limit.permitsPerSeconds());  
            limitMap.put(key, rateLimiter);  
            log.info("新建了令牌桶={},容量={}", key, limit.permitsPerSeconds());  
        }  
        rateLimiter = limitMap.get(key);  
        //拿一個(gè)令牌,拿不到會(huì)一直阻塞 
        double acquire = rateLimiter.acquire(1);  
        log.info("{},獲取令牌時(shí)間{}", key,LocalDateTime.now().format(dtf));  
        
        /*
        //是否能立即拿到令牌,不能則桶里沒(méi)有,還沒(méi)到一秒鐘,進(jìn)行限流
        boolean acquire = rateLimiter.tryAcquire();  
        if (!acquire) {  
        log.info("令牌桶={},獲取令牌失敗", key);  
        throw new RuntimeException(limit.msg());  
        }*/  
        
        }  
    return joinPoint.proceed();  
    }  
}

3.注解使用

@GetMapping("/limitTest")  
@Limit(key = "limitTest",permitsPerSeconds = 1,timeout = 1,msg = "觸發(fā)接口限流,請(qǐng)重試")  
public void limitTest(){  
    //其它邏輯代碼  
    //這里打印調(diào)用該接口執(zhí)行的時(shí)間,以便觀察限流  
    DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");  
    System.out.println(LocalDateTime.now().format(dtf));  
}

日志情況:

無(wú)論請(qǐng)求速度多快,一秒后才能處理請(qǐng)求。因?yàn)閞ateLimiter.acquire(1)拿不到,一直等待,會(huì)阻塞。 其它獲取令牌的方法感興趣可以按照上文方法詳情自行測(cè)試。

到此這篇關(guān)于基于Java編寫(xiě)一個(gè)限流工具類RateLimiter的文章就介紹到這了,更多相關(guān)Java限流工具類內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 純Java環(huán)境下實(shí)現(xiàn)將在線地圖路網(wǎng)數(shù)據(jù)轉(zhuǎn)為GeoJSON與WKT

    純Java環(huán)境下實(shí)現(xiàn)將在線地圖路網(wǎng)數(shù)據(jù)轉(zhuǎn)為GeoJSON與WKT

    這篇文章主要為大家詳細(xì)介紹了如何純Java環(huán)境下實(shí)現(xiàn)將在線地圖路網(wǎng)數(shù)據(jù)轉(zhuǎn)為GeoJSON與WKT,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下
    2026-02-02
  • 解決@JsonInclude(JsonInclude.Include.NON_NULL)不起作用問(wèn)題

    解決@JsonInclude(JsonInclude.Include.NON_NULL)不起作用問(wèn)題

    這篇文章主要介紹了解決@JsonInclude(JsonInclude.Include.NON_NULL)不起作用問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • Java設(shè)計(jì)模式之策略模式示例詳解

    Java設(shè)計(jì)模式之策略模式示例詳解

    這篇文章主要為大家詳細(xì)介紹了Java的策略模式,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-03-03
  • 接口重試的7種常用方案詳細(xì)介紹

    接口重試的7種常用方案詳細(xì)介紹

    這篇文章主要為大家詳細(xì)介紹了接口重試的7種常用方案,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以根據(jù)需求選擇
    2025-03-03
  • SpringBoot如何自定義線程池配置類

    SpringBoot如何自定義線程池配置類

    有時(shí)候我們?cè)陧?xiàng)目中做一些長(zhǎng)鏈路的跑批任務(wù)時(shí),基于Springboot項(xiàng)目的定時(shí)任務(wù),我們可以指定一個(gè)自定義的線程配置類進(jìn)行單獨(dú)提供給具體跑批任務(wù)使用,而不占用整個(gè)系統(tǒng)資源,這篇文章主要介紹了SpringBoot如何自定義線程池配置類,需要的朋友可以參考下
    2024-04-04
  • 理解java中的深復(fù)制和淺復(fù)制

    理解java中的深復(fù)制和淺復(fù)制

    這篇文章主要幫助大家理解java中的深復(fù)制和淺復(fù)制,對(duì)java中的深復(fù)制和淺復(fù)制進(jìn)行剖析,感興趣的小伙伴們可以參考一下
    2016-02-02
  • My eclipse 端口占用(9360)問(wèn)題解決辦法

    My eclipse 端口占用(9360)問(wèn)題解決辦法

    這篇文章主要介紹了My eclipse 工程發(fā)布時(shí)出現(xiàn)端口占用問(wèn)題解決辦法的相關(guān)資料,需要的朋友可以參考下
    2016-12-12
  • Spring Security OAuth 個(gè)性化token的使用

    Spring Security OAuth 個(gè)性化token的使用

    這篇文章主要介紹了Spring Security OAuth 個(gè)性化token的使用,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-02-02
  • RocketMQ事務(wù)消息保證消息的可靠性和一致性

    RocketMQ事務(wù)消息保證消息的可靠性和一致性

    RocketMQ事務(wù)消息是一種能夠保證消息傳遞的可靠性和一致性的消息傳遞模式。它通過(guò)引入“半消息”和“事務(wù)狀態(tài)”機(jī)制,實(shí)現(xiàn)了消息發(fā)送和本地事務(wù)執(zhí)行的原子性,從而確保了消息的可靠性和一致性
    2023-04-04
  • Spring+quartz實(shí)現(xiàn)定時(shí)發(fā)送郵件功能實(shí)例

    Spring+quartz實(shí)現(xiàn)定時(shí)發(fā)送郵件功能實(shí)例

    spring提供的定時(shí)發(fā)送郵件功能一直深受廣大web開(kāi)發(fā)者的喜愛(ài),這篇文章主要介紹了Spring+quartz實(shí)現(xiàn)定時(shí)發(fā)送郵件功能實(shí)例,有興趣的可以了解一下。
    2017-03-03

最新評(píng)論

宣恩县| 台州市| 新蔡县| 寿宁县| 霍山县| 灵宝市| 宁都县| 夏邑县| 出国| 瓮安县| 阿尔山市| 麟游县| 临颍县| 班戈县| 明星| 黄石市| 南阳市| 姚安县| 桐梓县| 屏东市| 买车| 阿拉尔市| 民丰县| 富蕴县| 新田县| 东宁县| 额敏县| 康定县| 西乌珠穆沁旗| 丁青县| 松溪县| 芜湖市| 东城区| 阳西县| 武乡县| 公安县| 昆山市| 镇宁| 英山县| 西乡县| 呼伦贝尔市|