如何优雅的实现接口限流?

首先限流,其实解决方案有很多,比如通过nginx配置,通过gateway网关进行限流,比如Spring Cloud GateWay整合熔断器实现限流

但是以上都是全局的,如何灵活的针对某些接口进行不同级别的限流呢?

方案一:令牌桶

如何需要用到这个方案需要先了解漏桶算法和令牌桶算法的区别

引入依赖

<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>18.0</version>
</dependency>

代码块

package com.sb.rateLimiter.service;import com.google.common.util.concurrent.RateLimiter;
import org.springframework.stereotype.Service;@Service
public class RateLimiterService {/*** 每秒只发出5个令牌*/RateLimiter rateLimiter = RateLimiter.create(5.0);/*** 尝试获取令牌* @return*/public boolean tryAcquire(){return rateLimiter.tryAcquire();}
}

自定义拦截器,在拦截器中实现限流

package com.sb.rateLimiter.interceptor;
import com.sb.rateLimiter.annotation.RateLimiterAnnotation;
import com.sb.rateLimiter.service.RateLimiterService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@Component
public class RateLimiterInterceptor implements HandlerInterceptor {@Resourceprivate RateLimiterService accessLimitService;private Logger logger = LoggerFactory.getLogger(RateLimiterInterceptor.class);@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {if (!(handler instanceof HandlerMethod)) {return true;}HandlerMethod handlerMethod = (HandlerMethod) handler;RateLimiterAnnotation rateLimiterAnnotation = handlerMethod.getMethod().getAnnotation(RateLimiterAnnotation.class);if(rateLimiterAnnotation == null) {return true;}if (!accessLimitService.tryAcquire()) {logger.info("限流中......");return false;}logger.info("请求成功");return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}

实现 WebMvcConfigurer 添加自定义拦截器

package com.sb.rateLimiter.config;
import com.sb.rateLimiter.interceptor.RateLimiterInterceptor;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;@SpringBootConfiguration
public class WebConfiguration implements WebMvcConfigurer {@Resourceprivate RateLimiterInterceptor rateLimiterInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(rateLimiterInterceptor).addPathPatterns("/**");}
}

自定义限流注解RateLimiterAnnotation

package com.sb.rateLimiter.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RateLimiterAnnotation {int rateLimiterNumber() default 1;
}

验证

package com.sb.rateLimiter.controller;
import com.sb.rateLimiter.annotation.RateLimiterAnnotation;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/api")
public class RateLimiterController {@RateLimiterAnnotation@RequestMapping(value = "/rateLimiterTest", method = RequestMethod.GET)public void rateLimiterTest() throws Exception {//业务逻辑;}

​​​​​​在这里插入图片描述

方案二:RedissonUtils.rateLimiter

这个方案其实和上面差不多都是通过一个注解实现接口限流的,只不过相较于上面的业务处理更加完善

自定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RateLimiter {//限流keyString key() default "rate_limit:";//限流时间,单位秒int time() default 60;//限流次数int count()default 100;//限流类型LimitType limitType() default  LimitType.DEFAULT
}

限流类型

public enum LimitType {// 默认策略全局限流DEFAULT,//根据请求者IP进行限流IP,//实例限流(集群多后端实例)CLUSTER

切面

@Befone("annotation(rateLimiter)")
public void doBefore(JoinPoint point, RateLimiter rateLimiter)//获取注解上的时间和计数int time = rateLimiter.time();int count = rateLimiter.count();//获取组合键String combineKey=this.getCombineKey(rateLimiter, point);try {//确定速率类型,这个枚举是redisson自带的枚举类RateType rateType = RateType.0VERALL;if(rateLimiter.LimiterType() == LimitType .CLUSTER){rateType  = RateType.PRE_CLIENT}// 调用RedissonUtils.rateLimiter方法进行限流处理Long number = RedissonUtils.rateLimiter(combineKey, rateType, count, time);if(number==-1){throw new RuntimeException("请求过于频繁~");};log.info("限制令牌 => {},剩余令牌 => {},緩存key =>'{}'"count,number,combineKey);}catch(Exception  e){throw new RnutimeException ("服务器限流异常,请稍后重试")}
}	
public String getCombineKey(RateLimiter rateLimiter, JoinPoint point){StringBuilder stringBuffer = new StringBuilder(rateLimiter.key());if(rateLimiter.limitType()== LimitType.IP){// 获取请求ipServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();HttpServletRequest request =  attributes.getRequest();String clientIp =ServletUtil.getClientIP(request);stringBuffer.append(clientIP).append("-");}else if(rateLimiter.limitType() == LimitType.CLUSTER){//获取客户端实例idstringBuffer.append(RedissonUtils.getClient().getId()).append("-");MethodSignature signature =(MethodSignature)point.getSignature();Method method = signature.getMethod();Class<?>targetClass = method.getDeclaringClass();stringBuffer.append(targetClass.getName()).append(" ").append(method.getName());return stringBuffer.toString();}
}

RedissonUtils的限流方法


/*** redis 限流管理器* @author xxx* @version 1.0* @date xxx*/@Service
public class RedissonUtils{/*** 限流操作** @param key 限流key* @param rateType 限流类型* @param rate 速率* @param rateInterval  速率间隔*/public void rateLimiter(String key, Ratetype rateType,int ratel, int rateInterval) {// 创建限流器RRateLimiter rateLimiter = redisson.getRateLimiter(key);rateLimiter.trySetRate(rateType, rate,rateInterval,RateIntervalUtil.SECONDES);// 获取令牌if (rateLimiter.tryAcquire()){return rateLimiter.availablePermits();} else {return  -1 ;}}
}

使用

@RestController
public class TestController {@RateLimiter(time=5,count =2)@GetMapping("/testLimit")public ResultV0<String> test(string name){return ResultV0.ok( data:"success");}	
}	

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/9032.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

超标量处理器设计:重排序缓存(ROB)

★超标量处理器的很多地方用到了重排序缓存&#xff0c;但是我对它不是很了解&#xff0c;所以我整理一下重排序缓存的知识点。 重排序缓存(ROB)在确保乱序执行的指令能够正确地完成和提交(Commit)&#xff0c;也可以用来寄存器重命名。 ROB是一个先进先出的表&#xff0c;每个…

Re_Lasso

from sklearn.linear_model import LassoCV, Lasso import pandas as pd from sklearn.model_selection import train_test_split from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score from sklearn.model_selection import GridSearchCV# 读取数据…

【备战软考(嵌入式系统设计师)】10 - 软件工程基础

这一部分的内容是概念比较多&#xff0c;不要理解&#xff0c;去感受。 涉及的知识点是嵌入式系统开发和维护的部分&#xff0c;也就是和管理相关的&#xff0c;而不是具体如何进行嵌入式系统开发的细节。 系统开发生命周期 按照顺序有下面几个阶段&#xff0c;我们主要要记…

12 华三的二层链路聚合

12 华三的二层链路聚合 配置思路 1. 配置二层静态聚合组 (1) 进入系统视图。 system-view (2) 创建二层聚合接口&#xff0c;并进入二层聚合接口视图。 interface bridge-aggregation interface-number [ lite ] 创建二层聚合接口后&#xff0c;系统将自动生成…

前端代码优化

嗯&#xff0c;最近pc更新了一版&#xff0c;目前没有什么活&#xff0c;就检查自己写的代码&#xff0c;去优化&#xff0c;发现有一个函数if嵌套了很多层&#xff0c;重复的代码也有很多&#xff0c;所以我就把重复的进行来了提取&#xff0c;以及一些其他优化 原代码 可以…

代码随想录算法训练营DAY46|C++动态规划Part8|139.单词拆分、多重背包理论基础、背包问题总结篇

文章目录 139.单词拆分思路CPP代码 多重背包理论基础处理输入把所有个数大于1的物品展开成1个开始迭代&#xff0c;计算dp数组代码优化 背包问题总结篇 139.单词拆分 力扣题目链接 文章讲解&#xff1a;139.单词拆分 视频讲解&#xff1a;你的背包如何装满&#xff1f;| LeetCo…

计算方法实验9:Romberg积分求解速度、位移

任务 输出质点的轨迹 ( x ( t ) , y ( t ) ) , t ∈ { 0.1 , 0.2 , 0.3 , . . . , 10 } (x(t), y(t)), t\in \{0.1, 0.2, 0.3, ..., 10\} (x(t),y(t)),t∈{0.1,0.2,0.3,...,10}&#xff0c;并在二维平面中画出该轨迹.请比较M分别取4, 8, 12, 16, 20 时&#xff0c;Romberg积分达…

go将时间对象切换到不同时区

编程的时候我们可能会遇到一些时区问题。在Go语言中&#xff0c;处理时区通常涉及到time包和time/tzdata包&#xff08;如果需要更新时区数据&#xff09;。这篇文章就写一下如何切换时区 一&#xff1a;直接上代码 package main import ( "fmt" "time&qu…

k8s持久化存储之OpenEBS

一、介绍 OpenEBS 是 CNCF 项目的一部分&#xff0c;采用 Apache v2 许可证。是 Kubernetes 部署使用最广泛且易用的开源存储解决方案。 目的&#xff1a; 让持久化工作负载的存储和存储服务完全集成到环境中&#xff0c;这样每个团队和工作负载都可以从控制的粒度和 Kubern…

蓝桥杯省三爆改省二,省一到底做错了什么?

到底怎么个事 这届蓝桥杯选的软件测试赛道&#xff0c;都说选择大于努力,软件测试一不卷二不难。省赛结束&#xff0c;自己就感觉稳啦&#xff0c;全部都稳啦。没想到一出结果&#xff0c;省三&#xff0c;g了。说落差&#xff0c;是真的有一点&#xff0c;就感觉和自己预期的…

mysql数据库和Oracle数据库除法或乘法,结果保留两位小数

在MySQL和Oracle数据库中&#xff0c;当你执行除法或乘法运算并希望结果保留两位小数时&#xff0c;你可以使用各自的内置函数来达到这个目的。 MySQL 在MySQL中&#xff0c;你可以使用ROUND()函数来四舍五入到指定的小数位数。例如&#xff0c;要保留两位小数&#xff0c;你…

汽车软件研发工具链丨怿星科技新产品重磅发布

“创新引领未来”聚焦汽车软件新基建&#xff0c;4月27日下午&#xff0c;怿星科技2024新产品发布会在北京圆满举行&#xff01;智能汽车领域的企业代表、知名大企业负责人、投资机构代表、研究机构代表齐聚现场&#xff0c;线上直播同步开启&#xff0c;共同见证怿星科技从单点…

经典回溯算法之N皇后问题

问题描述&#xff1a; 有一个N*N的棋盘&#xff0c;需要将N个皇后放在棋盘上&#xff0c;保证棋盘的每一行每一列每一左斜列每一右斜列都最多只能有一个皇后。 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如…

Java | Leetcode Java题解之第71题简化路径

题目&#xff1a; 题解&#xff1a; class Solution {public String simplifyPath(String path) {String[] names path.split("/");Deque<String> stack new ArrayDeque<String>();for (String name : names) {if ("..".equals(name)) {if …

【基于 PyTorch 的 Python 深度学习】5 机器学习基础(3)

前言 文章性质&#xff1a;学习笔记 &#x1f4d6; 学习资料&#xff1a;吴茂贵《 Python 深度学习基于 PyTorch ( 第 2 版 ) 》【ISBN】978-7-111-71880-2 主要内容&#xff1a;根据学习资料撰写的学习笔记&#xff0c;该篇主要介绍了单 GPU 加速和多 GPU 加速&#xff0c;以及…

代码随想录leetcode200题之哈希表

目录 1 介绍2 训练3 参考 1 介绍 本博客用来记录代码随想录leetcode200题中哈希表部分的题目。 2 训练 题目1&#xff1a;242. 有效的字母异位词 C代码如下&#xff0c; class Solution { public:bool isAnagram(string s, string t) {vector<int> cnt1(26, 0), cnt…

洛谷 P3379 [模板] 最近公共祖先(LCA)

【模板】最近公共祖先&#xff08;LCA&#xff09; 题目描述 如题&#xff0c;给定一棵有根多叉树&#xff0c;请求出指定两个点直接最近的公共祖先。 输入格式 第一行包含三个正整数 N , M , S N,M,S N,M,S&#xff0c;分别表示树的结点个数、询问的个数和树根结点的序号…

第十一节 LLAVA模型lora训练(包含lora权重预加载与源码解读)

文章目录 前言一、语言模型加载1、语言模型加载2、语言模型训练处理a、embeding处理b、语言模型lora训练处理lora参数配置peft配置语言模型lora参数c、语言模型tokenizer加载加载tokenizer设置对话开头语句二、视觉模型加载1、加载图像模型主函数源码解读2、initialize_vision_…

达梦数据库使用-外部表

文章目录 前言一、外部表使用1.外部表定义1.1 数据文件定义方式1.2控制文件定义方式2.外部表定义注意事项二、使用示例1.disql工具的脚本方式1.1 使用数据文件1.2 使用控制文件2.DM管理工具的图形方式2.1 创建目录2.2.创建指向数据文件的外部表2.3.创建指向控制文件的外部表三、…

英语口语情景对话视频软件分享!

在当今全球化的时代&#xff0c;英语已成为一种通用的国际语言。为了提高英语口语能力&#xff0c;越来越多的人选择使用英语口语情景对话视频软件。本文将为您推荐几款备受欢迎的英语口语情景对话视频软件&#xff0c;帮助您轻松提高英语口语水平。 AI外语陪练 AI外语陪练软件…