一、引言
在高并发的分布式系统中,如何有效地进行请求限流并防止重复提交,一直是开发者们面临的挑战。尤其是当需要同时针对多个维度(如IP、用户ID、用户名等)进行限流时,现有的一些解决方案往往难以满足灵活性和可维护性的要求。本篇文章将对Redis的多规则限流方案进行重构,探讨如何通过更符合单一职责原则的设计,提升代码的可读性与易用性,并为大家提供一套更加高效、实用的限流解决方案。
二、简介
本文详细讲解了如何利用Redis的Zset结构实现多规则限流,并包含在线演示、源码解析及讲解。针对之前版本在实际项目中的局限性(如防重复提交和限流配置不符合单一职责原则、RateLimiter仅能针对单一前缀key进行限流等问题),本文对代码进行了重构,以更简洁、合理的方式解决这些问题,为开发者提供更优的限流策略。 原文链接 : Redis如何多规则限流和防重复提交?
三、回顾代码
我们之前编写过的注解有 RateLimiter、RateRule , 我们对其进行了lua脚本编写,以及AOP切面编程,已达到以下效果 :
java
代码解读
复制代码
// 通过注解针对 ip 1分钟内访问10次 , 1小时内访问 20 次 , 1天内访问 60 次 @RateLimiter( rules = { @RateRule(count = 10, time = 1, timeUnit = TimeUnit.SECONDS), @RateRule(count = 20, time = 1, timeUnit = TimeUnit.HOURS), @RateRule(count = 60, time = 1, timeUnit = TimeUnit.DAYS) }, preventDuplicate = true )
针对以上点,我们对原有代码进行修改
四、重构限流以及防重复提交
项目最终结构
1. 重构注解
新增 RateLimiters 包含 RateLimiter[] , 这样可以方便针对 ip、用户名、局部方法,多个种类多规则限流。
java
代码解读
复制代码
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface RateLimiters { /** * 多个限流规则 */ RateLimiter[] rateLimiters(); }
删除原本的 RateLimiter 与防重复提交相关的属性 preventDuplicate 、preventDuplicateRule , 将防重复提交单独剥离出来。
java
代码解读
复制代码
@Target({ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface RateLimiter { /** * 限流类型 ( 默认全局 ) */ LimitTypeEnum limitTypeEnum() default LimitTypeEnum.GLOBAL; /** * 对应限流规则 */ RateRule[] rateRules(); /** * 在限流后,确定是否将请求加入黑名单 ( 用户 和 ip 都将进入黑名单 ) */ boolean addToBlacklist() default false; /** * 如果配置了 RateLimiters 中 message,以 RateLimiters 为准 */ ResultCode message() default ResultCode.REQUEST_RATE_LIMIT; }
而 RateRule 不进行过多修改,只修改了对应属性名。
java
代码解读
复制代码
@Target(ElementType.ANNOTATION_TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface RateRule { /** * 限流次数 */ long limit() default 10; /** * 限流时间 */ long timeDuration() default 60; /** * 限流时间单位 */ TimeUnit timeUnit() default TimeUnit.SECONDS; }
2. 针对重构后的 RateLimiters 进行切面编程
大致讲解一下 :
-
核心逻辑:boBefore 方法</