精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

API接口限流竟然如此簡單

開發 前端
我們已經成功實現了一個基于Redisson和Spring AOP的API接口限流功能。這個方案不僅簡單易懂,而且非常靈活,可以通過注解輕松地應用到任意方法上,并且支持多種限流策略(如全局限流、IP限流、集群限流等)。

簡介

API接口限流是一種流量控制技術,其目的是通過設置規則來限制客戶端對API接口的調用速率或總量,從而避免因過載而導致的服務性能下降甚至崩潰。

API限流在各種系統上都會有廣泛的使用場景,本文介紹一種非常簡單的實現API限流的方式。

為什么需要API接口限流?

  • 防止惡意攻擊:通過限制請求速率,可以有效抵御DDoS等類型的攻擊。
  • 優化資源使用:合理分配有限的計算資源給所有用戶,避免單個用戶占用過多資源。
  • 提升服務質量:保持服務響應時間在一個合理的范圍內,提高整體用戶體驗。

令牌桶

常見的API限流策略有令牌桶等算法。

令牌桶算法是一種常用的流量控制和限流機制,它通過模擬一個存放“令牌”的桶來控制請求的速率。

這個算法的核心思想是:系統以恒定的速率向桶中添加令牌,而每個請求在被處理之前必須從桶中獲取一個令牌。如果桶中有足夠的令牌,則請求可以繼續執行;如果沒有足夠的令牌(即桶為空),則請求要么等待直到有新的令牌產生,要么直接被拒絕。

實現API限流

這個算法很容易理解,但是要想手動實現一個令牌桶算法,并不是一個容易的事情。

還需要考慮:時間精度、并發處理、存儲管理、可配置性等問題。

Redis是一個常用的非關系型數據庫,非常適合用于緩存、實現限流等功能。本文介紹一個利用redis非常簡單的實現限流的功能,采用 AOP + 注解 + Redisson 框架實現。

1.定義限流注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RateLimiter {
    /**
     * 限流key,支持使用Spring el表達式來動態獲取方法上的參數值
     * 格式類似于  #code.id #{#code}
     */
    String key() default "";

    /**
     * 限流時間,單位秒
     */
    int time() default 60;

    /**
     * 限流次數
     */
    int count() default 100;

    /**
     * 限流類型
     */
    LimitType limitType() default LimitType.DEFAULT;

    /**
     * 提示消息
     */
    String message() default "服務器暫無資源處理新的請求,請稍后重試";
}
public enum LimitType {
    /**
     * 默認策略全局限流
     */
    DEFAULT,

    /**
     * 根據請求者IP進行限流
     */
    IP,

    /**
     * 實例限流(集群多后端實例)
     */
    CLUSTER
}

2.注解切面

@Slf4j
@Aspect
@Order(1)
public class RateLimiterAspect {
    private static final String LIMITER_KEY = "global:limiter:";

    /**
     * 定義spel表達式解析器
     */
    private final ExpressionParser parser = new SpelExpressionParser();
    /**
     * 定義spel解析模版
     */
    private final ParserContext parserContext = new TemplateParserContext();
    /**
     * 方法參數解析器
     */
    private final ParameterNameDiscoverer pnd = new DefaultParameterNameDiscoverer();

    /**
     * \@within(rateLimiter) 和 \@annotation(rateLimiter) 必須按照這個順序,才會優先執行方法上的注解
     */
    @Before("@within(rateLimiter) || @annotation(rateLimiter)")
    public void doBefore(JoinPoint point, RateLimiter rateLimiter) {
        if (rateLimiter == null) {
            // 如果方法上沒有,就從類上獲取注解
            Class<?> targetClass = point.getTarget().getClass();
            rateLimiter = targetClass.getAnnotation(RateLimiter.class);
            if (rateLimiter == null) {
                // 如果還是沒有獲取到注解,直接返回
                return;
            }
        }
        int time = rateLimiter.time();
        int count = rateLimiter.count();
        try {
            String combineKey = getCombineKey(rateLimiter, point);
            RateType rateType = RateType.OVERALL;
            if (rateLimiter.limitType() == LimitType.CLUSTER) {
                rateType = RateType.PER_CLIENT;
            }
            long number = RedisUtils.rateLimiter(combineKey, rateType, count, time);
            if (number == -1) {
                throw new RateLimiterException(rateLimiter.message());
            }
            log.debug("限制令牌 => {}, 剩余令牌 => {}, 緩存key => '{}'", count, number, combineKey);
        } catch (Exception e) {
            if (e instanceof RateLimiterException) {
                throw e;
            } else {
                throw new RuntimeException("服務器限流異常,請稍候再試", e);
            }
        }
    }

    private String getCombineKey(RateLimiter rateLimiter, JoinPoint point) {
        String key = rateLimiter.key();
        // 判斷 key 不為空 和 不是表達式
        if (StringUtils.hasText(key) && key.contains("#")) {
            MethodSignature signature = (MethodSignature) point.getSignature();
            Method targetMethod = signature.getMethod();
            Object[] args = point.getArgs();
            MethodBasedEvaluationContext context =
                new MethodBasedEvaluationContext(null, targetMethod, args, pnd);
            context.setBeanResolver(new BeanFactoryResolver(SpringUtil.getBeanFactory()));
            Expression expression;
            if (key.startsWith(parserContext.getExpressionPrefix()) && key.endsWith(parserContext.getExpressionSuffix())) {
                expression = parser.parseExpression(key, parserContext);
            } else {
                expression = parser.parseExpression(key);
            }
            key = expression.getValue(context, String.class);
        }
        StringBuilder str = new StringBuilder(LIMITER_KEY);
        HttpServletRequest request = getRequest();
        str.append(request.getRequestURI()).append(":");
        if (rateLimiter.limitType() == LimitType.IP) {
            // 獲取請求ip
            str.append(ServletUtil.getClientIP(request)).append(":");
        } else if (rateLimiter.limitType() == LimitType.CLUSTER) {
            // 獲取客戶端實例id
            str.append(RedisUtils.getClient().getId()).append(":");
        }
        return str.append(key).toString();
    }

    /**
     * 獲取request
     */
    private HttpServletRequest getRequest() {
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            return attributes.getRequest();
        } catch (Exception e) {
            return null;
        }
    }
}

3.Redisson 限流工具類

public class RedisUtils {

    private static final RedissonClient CLIENT = SpringUtil.getBean(RedissonClient.class);

    /**
     * 限流
     *
     * @param key          限流key
     * @param rateType     限流類型
     * @param rate         速率
     * @param rateInterval 速率間隔
     * @return -1 表示失敗
     */
    public static long rateLimiter(String key, RateType rateType, int rate, int rateInterval) {
        RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);
        // 如果限流器存在
        if (rateLimiter.isExists()) {
            // 獲取上次限流的配置信息
            RateLimiterConfig rateLimiterConfig = rateLimiter.getConfig();
            // 如果rateLimiterConfig的配置跟我們注解上面的值不一致,說明服務器重啟過,程序員又修改了限流的配置
            if (TimeUnit.SECONDS.convert(rateLimiterConfig.getRateInterval(), TimeUnit.MILLISECONDS) != rateInterval || rateLimiterConfig.getRate() != rate) {
                rateLimiter.delete();
                rateLimiter.trySetRate(rateType, rate, rateInterval, RateIntervalUnit.SECONDS);
            }
        }
        rateLimiter.trySetRate(rateType, rate, rateInterval, RateIntervalUnit.SECONDS);
        if (rateLimiter.tryAcquire()) {
            return rateLimiter.availablePermits();
        } else {
            return -1L;
        }
    }
    
    /**
     * 獲取客戶端實例
     */
    public static RedissonClient getClient() {
        return CLIENT;
    }
}

4.捕獲異常

@Data
@EqualsAndHashCode(callSuper = true)
public class RateLimiterException extends RuntimeException {

    /**
     * 錯誤提示
     */
    private final String message;

    public RateLimiterException(String message) {
        this.message = message;
    }

}
@Slf4j
@Order(1)
@RestControllerAdvice
public class LimiterExceptionHandler {

    /**
     * 限流異常
     */
    @ExceptionHandler({RateLimiterException.class})
    public Map<String, Object> handleRateLimiterException(RateLimiterException e, HttpServletRequest request) {
        log.error("請求地址'{}', 限流異常'{}'", request.getRequestURI(), e.getMessage());
        return result(e.getMessage());
    }

    private Map<String, Object> result(String msg) {
        HashMap<String, Object> result = new HashMap<>();
        result.put("code", 500);
        result.put("msg", msg);
        return result;
    }
}

到這里,已經實現了一個完整的API接口限流功能。

可以將之進一步封裝,作為一個springboot的starter,用于任意一個項目中。

小結

通過上述步驟,我們已經成功實現了一個基于Redisson和Spring AOP的API接口限流功能。這個方案不僅簡單易懂,而且非常靈活,可以通過注解輕松地應用到任意方法上,并且支持多種限流策略(如全局限流、IP限流、集群限流等)。

責任編輯:武曉燕 來源: Java技術指北
相關推薦

2020-12-28 07:47:35

動態代理AOP

2024-08-28 08:42:21

API接口限流

2021-12-09 09:02:53

JavaPDF文件iText

2021-12-08 10:36:46

JavaPDF文件

2024-09-09 11:35:35

2022-08-12 12:19:13

Cluster檢索集群

2020-06-19 17:49:23

建網

2018-08-27 08:31:25

InnoDBMySQL

2025-11-14 03:00:00

MySQL并發數據

2020-02-20 16:07:45

IT需求

2022-01-09 23:38:42

通信協議網絡

2022-02-23 20:42:40

HTMLmarkdownturndown

2022-07-08 14:35:05

Java組件LiteFlow

2010-08-25 21:50:36

配置DHCP

2021-05-14 07:45:07

Sentinel 接口限流

2020-11-24 08:02:26

API接口重構

2009-04-29 01:39:57

破解美萍萬象

2011-10-11 10:53:29

Ubuntu 11.1Gnome 3.2

2023-08-21 08:01:03

2011-09-15 10:35:12

Android應用IOS應用著裝搭配
點贊
收藏

51CTO技術棧公眾號

欧美激情一区二区三区四区 | 在线不卡免费av| 日本一区美女| 国产普通话bbwbbwbbw| 亚洲福利国产| 在线观看欧美日韩| 国产老头和老头xxxx×| 深夜成人影院| 一区二区成人在线视频 | www.av日韩| 久久午夜电影| 欧美乱妇高清无乱码| 欧美激情aaa| 天堂va在线高清一区| 色综合欧美在线视频区| 强开小嫩苞一区二区三区网站| 国产 欧美 自拍| 麻豆一区二区99久久久久| 韩国三级日本三级少妇99| 波多野结衣一二三四区| 精品国产一区二区三区成人影院 | 国产精品午夜在线| 含羞草久久爱69一区| 一二三区中文字幕| 亚洲欧美视频一区二区三区| 欧美成人午夜视频| 亚洲女同二女同志奶水| 欧美一级一片| 精品久久久久久久一区二区蜜臀| 亚洲色图 在线视频| 松下纱荣子在线观看| 亚洲免费伊人电影| 一区二区视频在线免费| 国产天堂在线| 9色porny自拍视频一区二区| 亚洲一区二区三区成人在线视频精品| 国产主播第一页| 最新日韩av| 欧美激情在线观看视频| 黄色香蕉视频在线观看| 第一会所亚洲原创| 国产一区二区黑人欧美xxxx| 亚洲成人av免费在线观看| 午夜视频一区二区在线观看| 欧美精品日韩精品| www.超碰97.com| 久久人体av| 欧美性生活久久| 一本色道无码道dvd在线观看| 国产福利电影在线播放| 亚洲国产一区视频| 国产资源在线免费观看| 免费电影网站在线视频观看福利| 亚洲欧美日本在线| 在线观看污视频| 中文字幕免费高清电视剧网站在线观看| 中文字幕欧美激情| 亚洲成人自拍视频| 69av在线| 亚洲精品欧美在线| 欧美大黑帍在线播放| 欧美黑人猛交的在线视频| 一区二区欧美在线观看| 欧美精品久久久久久久久久久| 黑人精品视频| 五月婷婷综合在线| 欧美牲交a欧美牲交aⅴ免费真| 依依综合在线| 欧美无乱码久久久免费午夜一区| 狠狠躁狠狠躁视频专区| gogo大尺度成人免费视频| 欧美一区二区三区色| 中文字幕制服丝袜| 欧美亚洲国产日韩| 国产亚洲福利一区| 欧美美女性生活视频| 欧美aⅴ99久久黑人专区| 欧美日韩成人黄色| 国产三级av片| 久久国产夜色精品鲁鲁99| 成人综合国产精品| 精品国产99久久久久久宅男i| 国产91在线|亚洲| 久久天堂国产精品| 在线激情免费视频| 一卡二卡欧美日韩| 浮妇高潮喷白浆视频| 亚洲伦乱视频| 日韩免费一区二区| 性欧美丰满熟妇xxxx性仙踪林| 国内黄色精品| 欧美另类极品videosbest最新版本 | 中文字幕不卡av| 欧美日韩在线观看成人| 亚洲精品系列| 国产精品青草久久久久福利99| 999国产精品视频免费| av中文字幕不卡| 亚洲国产综合自拍| 后进极品白嫩翘臀在线播放| 色综合久久99| 日本黄色www| 蜜桃一区二区三区| 欧美大片欧美激情性色a∨久久| 亚洲国产精一区二区三区性色| 天堂精品中文字幕在线| 亚洲a区在线视频| 秋霞av在线| 一区二区三区在线高清| 人人爽人人av| 欧美电影在线观看免费| 另类图片亚洲另类| 天天爽夜夜爽人人爽| 夫妻av一区二区| 一区二区不卡在线| 日韩福利一区| 亚洲国模精品一区| 免费一级片视频| 久久狠狠亚洲综合| 日韩在线三区| 久九九久频精品短视频| 精品国产成人在线影院| 无码人妻精品中文字幕| 视频精品一区二区| 精品伦精品一区二区三区视频| 18av在线视频| 欧美日韩视频在线一区二区 | 国产精品色哟哟网站| 欧美日韩在线一| 中文字幕av一区二区三区四区| 最近2019免费中文字幕视频三| 中文字幕激情小说| 不卡视频一二三| 日韩久久久久久久久久久久| 色狠狠一区二区三区| 一区二区中文字幕| 激情五月婷婷网| 久久亚洲免费视频| 成人一对一视频| 91蝌蚪精品视频| 久久99精品视频一区97| 国产欧美第一页| 亚洲天堂精品视频| 91丨九色丨蝌蚪| 天天天综合网| 国产一区二中文字幕在线看| 成人免费在线视频网| 色综合色综合色综合| 9.1成人看片免费版| 亚洲一区亚洲| 欧美日韩综合久久| 欧美色999| 在线免费观看羞羞视频一区二区| 无码人妻精品一区二区蜜桃色欲| 91色视频在线| 黄色高清无遮挡| 欧美码中文字幕在线| 国产精品美女网站| 尤物视频在线免费观看| 欧美日韩另类一区| 美女视频久久久| 国产成人在线免费观看| www插插插无码免费视频网站| 国产欧美自拍一区| 97国产在线视频| 黄色片在线免费看| 欧美日韩精品专区| 午夜写真片福利电影网| 成人激情免费网站| 超碰影院在线观看| 久久精品国产68国产精品亚洲| 国产日韩欧美另类| 性网站在线观看| 日韩成人高清在线| 亚洲精品一区二三区| **性色生活片久久毛片| av影片在线播放| 亚洲在线日韩| 日本视频一区二区在线观看| 日韩在线激情| 91精品国产91久久久久久| 黄色电影免费在线看| 在线电影院国产精品| 日本熟伦人妇xxxx| 国产精品美女视频| 中文字幕三级电影| 日本成人中文字幕| 日韩视频 中文字幕| 亚洲最好看的视频| 91手机视频在线观看| 嗯~啊~轻一点视频日本在线观看| 亚洲男女性事视频| 国产欧美久久久| 日本韩国欧美在线| 九九热精品免费视频| 国产欧美一二三区| 在线中文字日产幕| 日本在线不卡视频| 欧美久久在线观看| 国产精品久久久久一区二区三区厕所 | 国产精品视频一二三四区| 私拍精品福利视频在线一区| 91系列在线观看| 免费观看一级欧美片| 久久国产精品电影| 福利片在线观看| 精品国产亚洲一区二区三区在线观看| 啪啪小视频网站| 午夜精品久久久久久久久久| 五月天免费网站| 久久综合九色综合97婷婷| 永久免费看片在线观看| 奇米四色…亚洲| 国产成人精品视频免费看| 中文乱码免费一区二区三区下载| 日产精品一线二线三线芒果| 91麻豆精品激情在线观看最新 | 国产精品麻豆视频| 女同毛片一区二区三区| 国产精品一区免费在线观看| 浓精h攵女乱爱av| 99亚洲视频| 999一区二区三区| 羞羞答答成人影院www| 日本亚洲导航| 中文字幕亚洲影视| 国产伦精品一区二区三区视频黑人 | 国产十八熟妇av成人一区| 国产在线精品一区二区不卡了 | 国产精品久久久久久99| 一区二区三区国产精品| 999精品在线视频| 国产精品拍天天在线| 精品人妻无码一区二区三区换脸| 波多野结衣中文字幕一区二区三区 | 国产高清一区日本| 91精产国品一二三产区别沈先生| 日韩国产欧美在线播放| 日韩网站在线免费观看| 欧美搞黄网站| 色哟哟免费网站| 欧美破处大片在线视频| 日本黄色a视频| 国产精品久久观看| 亚洲午夜精品久久| 93在线视频精品免费观看| 亚洲精品高清国产一线久久| 国产探花在线精品| 日本在线观看一区| 欧美精品久久久久久| 日本免费一区二区三区| 全球成人免费直播| 亚洲综合网中心| 91精品啪在线观看国产81旧版| 亚洲免费不卡| 99精品视频在线观看播放| 在线看视频不卡| 亚洲情侣在线| 国产免费裸体视频| 国产日韩专区| 国产成人精品无码播放| 蜜臀av在线播放一区二区三区| 日日噜噜夜夜狠狠| 国产一区二区在线观看视频| 91性高潮久久久久久久| 国产成人一级电影| 精品国产一区在线| 久久久国产精华| 日日操免费视频| 亚洲色图欧洲色图| 国产精品111| 一本大道久久a久久综合| 在线免费观看视频网站| 91精品国产麻豆| 日本黄色免费视频| 国产一区二区激情| 伊人手机在线| 69影院欧美专区视频| 亚洲天堂1区| 99国产精品久久久久老师| 神马久久影院| 一区二区视频在线播放| 精品1区2区3区4区| 国产a级片免费观看| 国产在线乱码一区二区三区| jlzzjizz在线播放观看| 国产精品热久久久久夜色精品三区| 国产一区二区三区视频播放| 亚洲一区二区影院| 一级一级黄色片| 欧美mv日韩mv| jzzjzzjzz亚洲成熟少妇| 欧美大片在线看免费观看| 伊人色综合一区二区三区影院视频| 成人黄色大片在线免费观看| 国产精品色呦| 亚洲一区二区在线看| 99视频+国产日韩欧美| 中文字幕免费高清在线| 99久久精品国产精品久久| 少妇高潮惨叫久久久久| 欧美日韩午夜激情| 国产熟女一区二区丰满| 亚洲欧美日韩视频一区| 在线视频国产区| 国产精品福利网站| 凹凸成人在线| 中文字幕免费高| 麻豆成人精品| 秘密基地免费观看完整版中文| 日本一区二区三级电影在线观看 | 久久中文字幕人妻| 亚洲日本中文字幕区| 久操视频在线免费观看| 精品第一国产综合精品aⅴ| aiai在线| 国产999精品| 女仆av观看一区| 成人小视频在线观看免费| 蜜臀av性久久久久蜜臀aⅴ| 7788色淫网站小说| 夜夜操天天操亚洲| jizz中国女人| 色老头一区二区三区在线观看| 亚洲校园激情春色| 国产一区免费在线观看| 午夜日本精品| 伊人成人免费视频| 日韩一区在线免费观看| 中文字幕免费视频观看| 亚洲欧美日韩另类| 中文字幕在线视频久| 国产日韩一区二区| 伊人久久久大香线蕉综合直播| 亚洲成人手机在线观看| 亚洲欧洲日韩在线| 中文字幕第2页| 中文字幕精品视频| 成人福利一区二区| 亚洲国产精品一区二区第一页| 另类图片国产| 国产免费一区二区三区网站免费| 狠狠色狠狠色综合日日五| 偷拍精品一区二区三区| 午夜精品在线视频| 里番精品3d一二三区| 欧美亚洲日本一区二区三区| 成人午夜av电影| 黄色片视频网站| 精品视频久久久久久久| 亚洲精品福利电影| 日韩美女一区| 蜜臀va亚洲va欧美va天堂| 在线观看日本黄色| 欧美日本在线观看| caopeng在线| 97人人模人人爽人人喊38tv| 黄色亚洲免费| 国产乱了高清露脸对白| 在线视频国内一区二区| 成年人视频网站在线| 国产欧美一区二区三区在线看 | 中文字幕av影视| 久久精品国产2020观看福利| 精品国产18久久久久久二百| 国产精品视频二| av在线不卡观看免费观看| 天堂网一区二区三区| 国产一区二区三区三区在线观看 | 五月婷婷欧美激情| 在线播放欧美女士性生活| 亚洲区欧洲区| 精品免费国产| 美腿丝袜亚洲一区| 久久艹精品视频| 亚洲女人天堂色在线7777| 天然素人一区二区视频| 国产人妻互换一区二区| 成人精品gif动图一区| 波多野结衣一本一道| 久久国产一区二区三区| 国产毛片精品| 天天爽夜夜爽一区二区三区| 一区二区三区四区在线| 亚洲色偷精品一区二区三区| 国产免费一区视频观看免费| 欧美黄污视频| 国产黄色大片免费看| 日韩精品一区二区三区四区视频| 亚洲欧洲自拍| 97精品国产97久久久久久粉红| 久久综合视频网| 国产毛片久久久久| 日韩av免费在线| 亚洲欧美综合| 国精产品一区一区| 日韩大陆欧美高清视频区| 中文幕av一区二区三区佐山爱| 国产v片免费观看| 亚洲精品视频免费观看|