亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

SpringBoot?實現(xiàn)流控的操作方法

 更新時間:2024年12月02日 11:13:33   作者:小小工匠  
本文介紹了限流算法的基本概念和常見的限流算法,包括計數(shù)器算法、漏桶算法和令牌桶算法,還介紹了如何在Spring?Boot中使用Guava庫和自定義注解以及AOP實現(xiàn)接口限流功能,感興趣的朋友一起看看吧

概述

限流 簡言之就是當請求達到一定的并發(fā)數(shù)或速率,就對服務(wù)進行等待、排隊、降級、拒絕服務(wù)等操作。

限流算法

我們先簡單捋一捋限流算法

Spring Boot接口限流的常用算法及特點

SpringBoot接口限流的實現(xiàn)方法小結(jié)

計數(shù)器限流

漏桶算法

把水比作是請求,漏桶比作是系統(tǒng)處理能力極限,水先進入到漏桶里,漏桶里的水按一定速率流出,當流出的速率小于流入的速率時,由于漏桶容量有限,后續(xù)進入的水直接溢出(拒絕請求),以此實現(xiàn)限流

令牌桶算法

可以簡單地理解為醫(yī)去銀行辦理業(yè)務(wù),只有拿到號以后才可以進行業(yè)務(wù)辦理。

系統(tǒng)會維護一個令牌(token)桶,以一個恒定的速度往桶里放入令牌(token),這時如果有請求進來想要被處理,則需要先從桶里獲取一個令牌(token),當桶里沒有令牌(token)可取時,則該請求將被拒絕服務(wù)。令牌桶算法通過控制桶的容量、發(fā)放令牌的速率,來達到對請求的限制。

V1.0

上 guava

  <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>30.1-jre</version>
        </dependency>
package com.artisan.controller;
import com.artisan.annos.ArtisanLimit;
import com.google.common.util.concurrent.RateLimiter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;
/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */
@Slf4j
@RestController
@RequestMapping("/rateLimit")
public class RateLimitController {
    /**
     * 限流策略 : 1秒鐘1個請求
     */
    private final RateLimiter limiter = RateLimiter.create(1);
    private DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    @SneakyThrows
    @GetMapping("/test")
    public String testLimiter() {
        //500毫秒內(nèi),沒拿到令牌,就直接進入服務(wù)降級
        boolean tryAcquire = limiter.tryAcquire(500, TimeUnit.MILLISECONDS);
        if (!tryAcquire) {
            log.warn("BOOM 服務(wù)降級,時間{}", LocalDateTime.now().format(dtf));
            return "系統(tǒng)繁忙,請稍后再試!";
        }
        log.info("獲取令牌成功,時間{}", LocalDateTime.now().format(dtf));
        return "業(yè)務(wù)處理成功";
    }

我們可以看到RateLimiter的2個核心方法:create()、tryAcquire()

  • acquire() 獲取一個令牌, 改方法會阻塞直到獲取到這一個令牌, 返回值為獲取到這個令牌花費的時間
  • acquire(int permits) 獲取指定數(shù)量的令牌, 該方法也會阻塞, 返回值為獲取到這 N 個令牌花費的時間
  • tryAcquire() 判斷時候能獲取到令牌, 如果不能獲取立即返回 false
  • tryAcquire(int permits) 獲取指定數(shù)量的令牌, 如果不能獲取立即返回 false
  • tryAcquire(long timeout, TimeUnit unit) 判斷能否在指定時間內(nèi)獲取到令牌, 如果不能獲取立即返回 false
  • tryAcquire(int permits, long timeout, TimeUnit unit) 同上

測試一下

V2.0 自定義注解+AOP實現(xiàn)接口限流

1.0的功能實現(xiàn)了,但是業(yè)務(wù)代碼和限流代碼混在一起,非常的不美觀。

搞依賴

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

搞自定義限流注解

package com.artisan.annos;
import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;
/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface ArtisanLimit {
    /**
     * 資源的key,唯一
     * 作用:不同的接口,不同的流量控制
     */
    String key() default "";
    /**
     * 最多的訪問限制次數(shù)
     */
    double permitsPerSecond();
    /**
     * 獲取令牌最大等待時間
     */
    long timeout();
    /**
     * 獲取令牌最大等待時間,單位(例:分鐘/秒/毫秒) 默認:毫秒
     */
    TimeUnit timeunit() default TimeUnit.MILLISECONDS;
    /**
     * 得不到令牌的提示語
     */
    String message() default "系統(tǒng)繁忙,請稍后再試.";
}

搞AOP

使用AOP切面攔截限流注解

package com.artisan.aop;
import com.artisan.annos.ArtisanLimit;
import com.artisan.resp.ResponseCode;
import com.artisan.resp.ResponseData;
import com.artisan.utils.WebUtils;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.RateLimiter;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Map;
/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */
@Slf4j
@Aspect
@Component
public class ArtisanLimitAop {
    /**
     * 不同的接口,不同的流量控制
     * map的key為 ArtisanLimit.key
     */
    private final Map<String, RateLimiter> limitMap = Maps.newConcurrentMap();
    @Around("@annotation(com.artisan.annos.ArtisanLimit)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        //拿ArtisanLimit的注解
        ArtisanLimit limit = method.getAnnotation(ArtisanLimit.class);
        if (limit != null) {
            //key作用:不同的接口,不同的流量控制
            String key = limit.key();
            RateLimiter rateLimiter = null;
            //驗證緩存是否有命中key
            if (!limitMap.containsKey(key)) {
                // 創(chuàng)建令牌桶
                rateLimiter = RateLimiter.create(limit.permitsPerSecond());
                limitMap.put(key, rateLimiter);
                log.info("新建了令牌桶={},容量={}", key, limit.permitsPerSecond());
            }
            rateLimiter = limitMap.get(key);
            // 拿令牌
            boolean acquire = rateLimiter.tryAcquire(limit.timeout(), limit.timeunit());
            // 拿不到命令,直接返回異常提示
            if (!acquire) {
                log.warn("令牌桶={},獲取令牌失敗", key);
                this.responseFail(limit.message());
                return null;
            }
        }
        return joinPoint.proceed();
    }
    /**
     * 直接向前端拋出異常
     *
     * @param msg 提示信息
     */
    private void responseFail(String msg) {
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        ResponseData<Object> resultData = ResponseData.fail(ResponseCode.LIMIT_ERROR.getCode(), msg);
        WebUtils.writeJson(response, resultData);
    }
}

用上驗證

   @GetMapping("/test2")
    @ArtisanLimit(key = "testLimit2", permitsPerSecond = 1, timeout = 500, timeunit = TimeUnit.MILLISECONDS, message = "test2 當前排隊人數(shù)較多,請稍后再試!")
    public String test2() {
        log.info("令牌桶test2獲取令牌成功");
        return "test2 ok";
    }

源碼

https://github.com/yangshangwei/boot2

到此這篇關(guān)于SpringBoot 實現(xiàn)流控的操作方法的文章就介紹到這了,更多相關(guān)SpringBoot流控內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java實現(xiàn)OTP(動態(tài)口令)服務(wù)

    Java實現(xiàn)OTP(動態(tài)口令)服務(wù)

    OTP是一種動態(tài)生成的短時有效密碼,用于身份驗證,通常在登錄或執(zhí)行敏感操作時提供額外的安全保障,本文主要介紹了Java實現(xiàn)OTP(動態(tài)口令)服務(wù),感興趣的可以了解一下
    2025-03-03
  • Java獲取指定字符串出現(xiàn)次數(shù)的方法

    Java獲取指定字符串出現(xiàn)次數(shù)的方法

    這篇文章主要為大家詳細介紹了Java獲取指定字符串出現(xiàn)次數(shù)的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • Windows10系統(tǒng)下修改jar中的文件并重新打包成jar文件然后運行的操作步驟

    Windows10系統(tǒng)下修改jar中的文件并重新打包成jar文件然后運行的操作步驟

    這篇文章主要介紹了Windows10系統(tǒng)下修改jar中的文件并重新打包成jar文件然后運行的操作步驟,文中通過圖文結(jié)合的形式給大家講解的非常詳細,對大家的學習或工作有一定的幫助,需要的朋友可以參考下
    2024-08-08
  • 一文帶你掌握Java中Scanner類的使用

    一文帶你掌握Java中Scanner類的使用

    Scanner類是java.util包中的一個類,常用于控制臺的輸入,當需要使用控制臺輸入時即可調(diào)用這個類。本文將通過一些簡單的例子為大家介紹一下Java中Scanner類的使用,需要的可以參考一下
    2023-04-04
  • Spring Boot容器加載時執(zhí)行特定操作(推薦)

    Spring Boot容器加載時執(zhí)行特定操作(推薦)

    這篇文章主要介紹了Spring Boot容器加載時執(zhí)行特定操作及spring內(nèi)置的事件,需要的朋友可以參考下
    2018-01-01
  • 在SpringBoot中整合數(shù)據(jù)源的示例詳解

    在SpringBoot中整合數(shù)據(jù)源的示例詳解

    這篇文章主要介紹了在SpringBoot中如何整合數(shù)據(jù)源,本文介紹了如何在SpringBoot項目中整合常見的數(shù)據(jù)源,包括JdbcTemplate、MyBatis和JPA,并探討了如何配置和使用多數(shù)據(jù)源,需要的朋友可以參考下
    2023-06-06
  • Mybatis的介紹、基本使用、高級使用

    Mybatis的介紹、基本使用、高級使用

    這篇文章主要介紹了Mybatis的介紹、基本使用、高級使用,Mybatis是一款半自動的ORM持久層框架,具有較高的SQL靈活性,如何使用看這篇就夠了,需要的朋友可以參考下
    2023-03-03
  • 關(guān)于Maven依賴沖突解決之exclusions

    關(guān)于Maven依賴沖突解決之exclusions

    這篇文章主要介紹了關(guān)于Maven依賴沖突解決之exclusions用法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Java設(shè)計模式之策略模式示例詳解

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

    這篇文章主要為大家詳細介紹了Java的策略模式,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • 解決Request.getParameter獲取不到特殊字符bug問題

    解決Request.getParameter獲取不到特殊字符bug問題

    這篇文章主要介紹了解決Request.getParameter獲取不到特殊字符bug問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07

最新評論