当前位置: 首页 > news >正文

Redis 限流解决方案:结合 Lua 脚本、AOP 和自定义注解的实现

目录

  • 一、概述
  • 二、技术栈
  • 三、配置项
    • 1、配置文件
    • 2、Redis 配置类
  • 四、流量控制功能设计
    • 1、需求分析
    • 2、设计思路
    • 3、自定义注解
    • 4、AOP 切面实现
    • 5、Lua 脚本
    • 6、示例 Controller
  • 五、总结

一、概述

为了保护系统的稳定性,避免在高并发情况下系统崩溃,我们设计并实现了一个基于 RedisLua 脚本AOP反射自定义注解的限流组件。该组件能灵活配置并支持高可用、高并发的流量控制。

二、技术栈

  • Redis:作为流量控制的基础存储,用于计数和过期控制。
  • Lua 脚本:通过 Lua 脚本来保证限流操作的原子性,避免因并发请求引起的竞争条件。
  • AOP:通过切面编程将流量控制逻辑与业务代码解耦,做到高效且优雅的控制。
  • 自定义注解:为不同的业务方法灵活添加限流控制,支持高度可配置性。

三、配置项

1、配置文件

首先是 Redis 配置文件(application.properties):

# Redis 配置
spring.data.redis.database=0
spring.data.redis.host=192.168.121.140
spring.data.redis.port=6379
spring.data.redis.password=
spring.data.redis.lettuce.pool.max-active=8
spring.data.redis.lettuce.pool.max-wait=-1ms
spring.data.redis.lettuce.pool.max-idle=8
spring.data.redis.lettuce.pool.min-idle=0

2、Redis 配置类

RedisConfig 配置类主要完成 Redis 连接池及序列化方式的设置:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(lettuceConnectionFactory);redisTemplate.setKeySerializer(new StringRedisSerializer());redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.afterPropertiesSet();return redisTemplate;}
}

四、流量控制功能设计

1、需求分析

  1. 可配置:支持随时调整限流的时间和次数。
  2. 可插拔:支持按业务需求选择不同的限流策略。
  3. 可通用:不和代码业务逻辑写死,可单独配置
  4. 高可用:在高并发下仍能保证流量控制的稳定性。

2、设计思路

  1. 自定义注解:通过 @RedisLimitAnnotation 注解来标识需要限流的方法,并配置限流的时间窗口、请求次数及提示消息。
  2. Lua 脚本:通过 Redis Lua 脚本实现原子操作,确保限流操作的可靠性。
  3. AOP 切面:利用 AOP 切面来拦截带有限流注解的方法,进行限流操作。

3、自定义注解

RedisLimitAnnotation 注解用于标识需要限流的方法,提供了可配置的属性。

import java.lang.annotation.*;/*** 限流注解,用于标识需要限流的方法*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface RedisLimitAnnotation {/*** 资源的唯一 key*/String key() default "";/*** 最大访问次数*/long permitsPerSecond() default 2;/*** 过期时间,单位秒,默认60*/long expire() default 60;/*** 限流时的提示消息*/String msg() default "系统繁忙,请稍后再试!";
}

4、AOP 切面实现

RedisLimitAop 类实现了基于 AOP 的限流逻辑,拦截带有 @RedisLimitAnnotation 注解的方法,执行 Redis 限流操作。

@Slf4j
@Aspect
@Component
public class RedisLimitAop {@Resourceprivate StringRedisTemplate stringRedisTemplate;private DefaultRedisScript<Long> redisLuaScript;@PostConstructpublic void init() {redisLuaScript = new DefaultRedisScript<>();redisLuaScript.setResultType(Long.class);redisLuaScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("rateLimiter.lua")));}@Around("@annotation(com.donglin.interview2.annotations.RedisLimitAnnotation)")public Object around(ProceedingJoinPoint joinPoint) {MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();RedisLimitAnnotation redisLimitAnnotation = method.getAnnotation(RedisLimitAnnotation.class);if (redisLimitAnnotation != null) {String key = redisLimitAnnotation.key();long limit = redisLimitAnnotation.permitsPerSecond();long expire = redisLimitAnnotation.expire();List<String> keys = new ArrayList<>();keys.add(key);Long count = stringRedisTemplate.execute(redisLuaScript, keys, String.valueOf(limit), String.valueOf(expire));if (count != null && count == 0) {return redisLimitAnnotation.msg();}}try {return joinPoint.proceed();} catch (Throwable e) {throw new RuntimeException(e);}}
}

5、Lua 脚本

rateLimiter.lua 脚本用于实现 Redis 限流逻辑。它会检查当前访问次数,如果超过限流次数,则返回 0,否则自增访问计数并设置过期时间。

-- 获取当前 key
local key = KEYS[1]
-- 获取最大访问次数
local limit = tonumber(ARGV[1])
-- 获取当前访问次数
local currentLimit = tonumber(redis.call('get', key) or "0")-- 超过访问次数限制,返回 0
if currentLimit + 1 > limit thenreturn 0
else-- 自增访问次数redis.call('INCRBY', key, 1)-- 设置过期时间redis.call('EXPIRE', key, ARGV[2])return currentLimit + 1
end

6、示例 Controller

通过在 Controller 方法上添加 @RedisLimitAnnotation 注解,控制请求的频率。

@Slf4j
@RestController
public class RedisLimitController {@GetMapping("/redis/limit/test")@RedisLimitAnnotation(key = "redisLimit", permitsPerSecond = 3, expire = 10, msg = "当前排队人数较多,请稍后再试!")public String redisLimit() {return "正常业务返回,订单流水:" + IdUtil.fastUUID();}
}

五、总结

通过 Redis、Lua 脚本、AOP 以及自定义注解的组合,我们实现了一个高效且灵活的流量控制方案。此方案不仅支持高并发场景,还具备高度的可配置性和可插拔性,能够应对各种业务需求。

http://www.dtcms.com/a/490292.html

相关文章:

  • 游戏画面卡顿残影?这款电竞显示器610Hz + 4K OLED
  • COLMAP原理讲解与使用教程
  • 定位守护童年,科技构筑安全屏障
  • AWS EC2 Jenkins 自动化部署与 Python 环境管理
  • Linux中快速部署Elasticsearch(基础TLS配置)
  • 2025吉比特-游戏引擎开发-一面复盘
  • java数据结构--List的介绍
  • 网站主页不收录肥城房产网
  • 计算机视觉(opencv)——基于 MediaPipe 的实时面部表情识别
  • C++设计模式_行为型模式_观察者模式Observer(发布-订阅(Publish-Subscribe))
  • 怎么解决ModuleNotFoundError: No module named ‘Cython‘
  • 电子商务网站规划流程手机主题制作网站
  • 微信小程序 Button 组件 open-type 完全指南:从用户信息获取到客服分享的实战应用
  • 阿里云白皮书-架构
  • Rokid 开发空间小程序 实战
  • RAG系统搭建指南:5种主流框架的易用性和效果对比
  • 网站后台怎么添加代码哪里有免费的域名注册建网站
  • Jetson AGX Orin+GMSL+AI视觉开发套件,支持自动驾驶,机器人,工业视觉等应用
  • 【JETSON+FPGA+GMSL+AI】自动驾驶与移动机器人的摄像头如何实现高精度时间同步?
  • Java 设计模式——建造者模式:从原理到实战的极简指南
  • 怎么找做企业网站的雁塔区住房和城乡建设局网站
  • 哈尔滨电商企业服务器托管方案
  • 机器学习基础入门(第五篇):半监督学习与强化学习
  • 建网站解决方案代运营网店公司
  • 网站建设网页制作软件wordpress 移动到回收站发生错误
  • 5G安全深入解析:EAP-AKA、EAP-AKA‘与5G-AKA详解
  • YOLO 系列演进:从 V1 到 V2 的目标检测革命
  • 云栖实录|MaxCompute全新升级:AI时代的原生数据仓库
  • 基于Multi-Agent开发的SmartCare系统自动化运维管家
  • 终结浏览器隐患:自动化安全审计与报表