使用 redis 实现分布式接口限流注解 RedisLimit
前言
- 很多时候,由于种种不可描述的原因,我们需要针对单个接口实现接口限流,防止访问次数过于频繁。这里就用 redis+aop 实现一个限流接口注解
@RedisLimit 代码
点击查看RedisLimit注解代码
import java.lang.annotation.*;
/**
* 功能:分布式接口限流注解
* @author love ice
* @create 2023-09-18 15:43
*/
@Target({ElementType.TYPE,ElementType.METHOD})
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisLimit {
/**
* redis中唯一key,一般用方法名字做区分
* 作用: 针对不同接口,做不同的限流控制
*/
String key() default "";
/**
* 限流时间内允许访问次数 默认1
*/
long permitsPerSecond() default 1;
/**
* 限流时间,单位秒 默认60秒
*/
long expire() default 60;
/**
* 限流提示信息
*/
String msg() default "接口限流,请稍后重试";
}
AOP代码
点击查看aop代码
import com.aliyuncs.utils.StringUtils;
import com.test.redis.Infrastructure.annotation.RedisLimit;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scripting.support.ResourceScriptSource;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* redis限流切面
*
* @author love ice
* @create 2023-09-18 15:44
*/
@Slf4j
@Aspect
@Component
public class RedisLimitAop {
@Autowired
private StringRedisTemplate stringRedisTemplate;
private DefaultRedisScript<Long> redisScript;
@PostConstruct
public void init() {
redisScript = new DefaultRedisScript<>();
redisScript.setResultType(Long.class);
// 执行 lua 脚本
ResourceScriptSource resourceScriptSource = new ResourceScriptSource(new ClassPathResource("rateLimiter.lua"));
redisScript.setScriptSource(resourceScriptSource);
}
@Pointcut("@annotation(com.test.redis.Infrastructure.annotation.RedisLimit)")
private void check() {
}
@Before("check()")
private void before(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
// 拿到 RedisLimit 注解,如果存在则说明需要限流
RedisLimit redisLimit = method.getAnnotation(RedisLimit.class);
if (redisLimit != null) {
// 获取 redis 的 key
String key = redisLimit.key();
String className = method.getDeclaringClass().getName();
String name = method.getName();
String limitKey = key + className + name;
log.info("限流的key:{}", limitKey);
if (StringUtils.isEmpty(key)) {
// 这里是自定义异常,为了方便写成了 RuntimeException
throw new RuntimeException("code:101,msg:接口中 key 参数不能为空");
}
long limit = redisLimit.permitsPerSecond();
long expire = redisLimit.expire();
// 把 key 放入 List 中
List<String> keys = new ArrayList<>(Collections.singletonList(key));
Long count = stringRedisTemplate.execute(redisScript, keys, String.valueOf(limit), String.valueOf(expire));
log.info("Access try count is {} for key ={}", count, keys);
if (count != null && count == 0) {
log.debug("令牌桶={}, 获取令牌失效,接口触发限流", key);
throw new RuntimeException("code:10X, redisLimit.msg()");
}
}
}
}
lua脚本代码
注意:脚本代码是放在 resources 文件下的,它的类型是 txt,名称后缀是lua。如果你不想改名称,就使用我写好的全名--> rateLimiter.lua
点击查看脚本代码
--获取KEY
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local curentLimit = tonumber(redis.call('get', key) or "0")
if curentLimit + 1 > limit
then return 0
else
-- 自增长 1
redis.call('INCRBY', key, 1)
-- 设置过期时间
redis.call('EXPIRE', key, ARGV[2])
return curentLimit + 1
end
最后为了照顾纯小白,给大家看一下我的目录结构
使用 redis 实现分布式接口限流注解 RedisLimit的更多相关文章
- SpringBoot使用自定义注解+AOP+Redis实现接口限流
为什么要限流 系统在设计的时候,我们会有一个系统的预估容量,长时间超过系统能承受的TPS/QPS阈值,系统有可能会被压垮,最终导致整个服务不可用.为了避免这种情况,我们就需要对接口请求进行限流. 所以 ...
- 服务限流 -- 自定义注解基于RateLimiter实现接口限流
1. 令牌桶限流算法 令牌桶会以一个恒定的速率向固定容量大小桶中放入令牌,当有浏览来时取走一个或者多个令牌,当发生高并发情况下拿到令牌的执行业务逻辑,没有获取到令牌的就会丢弃获取服务降级处理,提示一个 ...
- 基于注解的接口限流+统一session认证
代码心得: 一个基本的做法:对于用户身份认证做到拦截器里,针对HandlerMethod进行统一拦截认证,根据方法上的注解标识,判别是否需要身份验证,并将查找出来的User实体存入ThreadLoca ...
- 库存秒杀问题-redis解决方案- 接口限流
<?php/** * Created by PhpStorm. * redis 销量超卖秒杀解决方案 * redis 文档:http://doc.redisfans.com/ * ab -n 1 ...
- Java分布式IP限流和防止恶意IP攻击方案
前言 限流是分布式系统设计中经常提到的概念,在某些要求不严格的场景下,使用Guava RateLimiter就可以满足.但是Guava RateLimiter只能应用于单进程,多进程间协同控制便无能为 ...
- Guava-RateLimiter实现令牌桶控制接口限流方案
一.前言 对于一个应用系统来说,我们有时会遇到极限并发的情况,即有一个TPS/QPS阀值,如果超了阀值可能会导致服务器崩溃宕机,因此我们最好进行过载保护,防止大量请求涌入击垮系统.对服务接口进行限流可 ...
- 【高并发】亿级流量场景下如何为HTTP接口限流?看完我懂了!!
写在前面 在互联网应用中,高并发系统会面临一个重大的挑战,那就是大量流高并发访问,比如:天猫的双十一.京东618.秒杀.抢购促销等,这些都是典型的大流量高并发场景.关于秒杀,小伙伴们可以参见我的另一篇 ...
- SpringCloud(8)---zuul权限校验、接口限流
zuul权限校验.接口限流 一.权限校验搭建 正常项目开发时,权限校验可以考虑JWT和springSecurity结合进行权限校验,这个后期会总结,这里做个基于ZuulFilter过滤器进行一个简单的 ...
- 【Dnc.Api.Throttle】适用于.Net Core WebApi接口限流框架
Dnc.Api.Throttle 适用于Dot Net Core的WebApi接口限流框架 使用Dnc.Api.Throttle可以使您轻松实现WebApi接口的限流管理.Dnc.Api.Thr ...
- Spring Cloud Alibaba基础教程:使用Sentinel实现接口限流
最近管点闲事浪费了不少时间,感谢网友libinwalan的留言提醒.及时纠正路线,继续跟大家一起学习Spring Cloud Alibaba. Nacos作为注册中心和配置中心的基础教程,到这里先告一 ...
随机推荐
- git 访问仓库错误
通过https访问git出现错误, failed: Error in the pull function 尝试将https改为http
- PHP echo 和 print 语句
在 PHP 中,有两种基本的输出方法:echo 和 print. PHP echo 和 print 语句 echo 和 print 之间的差异: echo - 能够输出一个以上的字符串 print - ...
- Prometheus-5:relabel标签重新打标
Prometheus relabel重新打标 对target重新打标是在数据抓取之前动态重写target标签的强大工具,在每个数据抓取配置中,可以定义多个relabel步骤,它们将按照定义的顺序依次执 ...
- 使用 vscode 远程登陆自己的电脑/服务器 (不需要内网穿透 😇)
问题背景 最近有远程调试的需求,从笔记本连入配置比较高的电脑(windows)运行代码,查阅资料后,了解到大致就是两个方法: 共享屏幕远程控制,如 to desk, 向日葵 内网穿透 + ssh 第一 ...
- WPF 中WebBrowser 控件的“允许阻止的内容”修复(引用本地的html页)
解决方法:(个人理解:导致原因就是iE安全机制的问题吧).在你的HTML里面第一行加: <!-- saved from url=(0014)about:internet -->具体原因可以 ...
- 三 APPIUM Android自动化 测试初体验(转)
1.创建一个maven项目 成功新建工程: 编辑pom.xml,在<dependencies></dependencies>下添加appium相关依赖: <depende ...
- trick : Trygub num
trick大意 我对于这个trick的理解为:支持位运算的高精度 维护一个以 \(b\)为基数的大数 \(N\),并支持以下功能: 给定(可能是负)整数 \(|x|, |y| \leqslant n\ ...
- Java不能操作内存?Unsafe了解一下
前言 C++可以动态的分类内存(但是得主动释放内存,避免内存泄漏),而java并不能这样,java的内存分配和垃圾回收统一由JVM管理,是不是java就不能操作内存呢?当然有其他办法可以操作内存,接下 ...
- struct(C# 参考)
struct 类型是一种值类型,通常用来封装小型相关变量组,例如,矩形的坐标或库存商品的特征. 下面的示例显示了一个简单的结构声明. 1 public struct Book 2 { 3 public ...
- 带你读论文丨Fuzzing漏洞挖掘详细总结 GreyOne
本文分享自华为云社区<[论文阅读] (03) 清华张超老师 - Fuzzing漏洞挖掘详细总结 GreyOne>,作者: eastmount. 一.传统的漏洞挖掘方法 演讲题目: 数据流敏 ...