Skip to content

限流模块

鸣谢

本功能最初由 Gitee@KAI(莫愁) 大佬提交 PR,感谢大佬的开源贡献。

PR:https://gitee.com/continew/continew-starter/pulls/22

简介

continew-starter-ratelimiter 是 ContiNew Starter 提供的基于 AOP 和 Redisson 内置分布式限流器(采用令牌桶算法)整合实现的分布式限流模块,提供开箱即用的分布式限流解决方案。

主要特性

  • 基于 Redisson 的分布式限流器实现(采用令牌桶算法),以恒定速率生成令牌,每个请求需要获取令牌才能被处理
  • 支持灵活的多维度限流场景:
    • IP 限流(限制单个客户端访问频率)
    • 单节点限流(保障单实例服务稳定性)
    • 全局限流(集群环境下的全局速率控制)
  • 提供 SpEL 表达式支持,支持动态解析请求参数进行限流 key 配置
    • 示例:@RateLimiter(key = "#userId")
  • 支持限流器链配置,可组合多个限流策略进行多级流量控制

快速开始

引入依赖

pom.xml
xml
<dependency>  <groupId>top.continew.starter</groupId>  <artifactId>continew-starter-ratelimiter</artifactId> </dependency>

添加配置

配置详情请查看:top.continew.starter.ratelimiter.autoconfigure.RateLimiterProperties

application.yml
yaml
--- ### 限流器配置 continew-starter:  rate-limiter:  # 是否启用(默认:已启用)  enabled: true  # 限流统一 Key 前缀(默认:RateLimiter)  key-prefix: RateLimiter

使用 @RateLimiter 注解

在需要限流处理的接口上添加 top.continew.starter.ratelimiter.annotation.@RateLimiter 注解,支持通过 @RateLimiters 注解组合多个限流策略。

下方以预防短信炸弹的限流策略为例:

  1. 同一号码同一模板,1分钟2条,1小时8条,24小时20条
  2. 同一号码所有模板 24 小时 100 条
  3. 同一 IP 每分钟限制发送 30 条

温馨提示

短信炸弹不能单凭限流器进行预防,还要结合行为验证码等其他措施,下方仅示例了短信炸弹的限流策略。

java
@Operation(summary = "获取短信验证码", description = "发送验证码到指定手机号") @GetMapping("/sms") @RateLimiters({  @RateLimiter(name = CacheConstants.CAPTCHA_KEY_PREFIX + "MIN", key = "#phone + ':' + T(cn.hutool.extra.spring.SpringUtil).getProperty('captcha.sms.templateId')", rate = 2, interval = 1, unit = TimeUnit.MINUTES, message = "获取验证码操作太频繁,请稍后再试"),  @RateLimiter(name = CacheConstants.CAPTCHA_KEY_PREFIX + "HOUR", key = "#phone + ':' + T(cn.hutool.extra.spring.SpringUtil).getProperty('captcha.sms.templateId')", rate = 8, interval = 1, unit = TimeUnit.HOURS, message = "获取验证码操作太频繁,请稍后再试"),  @RateLimiter(name = CacheConstants.CAPTCHA_KEY_PREFIX + "DAY'", key = "#phone + ':' + T(cn.hutool.extra.spring.SpringUtil).getProperty('captcha.sms.templateId')", rate = 20, interval = 24, unit = TimeUnit.HOURS, message = "获取验证码操作太频繁,请稍后再试"),  @RateLimiter(name = CacheConstants.CAPTCHA_KEY_PREFIX, key = "#phone", rate = 100, interval = 24, unit = TimeUnit.HOURS, message = "获取验证码操作太频繁,请稍后再试"),  @RateLimiter(name = CacheConstants.CAPTCHA_KEY_PREFIX, key = "#phone", rate = 30, interval = 1, unit = TimeUnit.MINUTES, type = LimitType.IP, message = "获取验证码操作太频繁,请稍后再试") }) public R getSmsCaptcha(@NotBlank(message = "手机号不能为空") @Mobile String phone) {  // ...略  }

@RateLimiter 注解

RateLimiter.java
java
@Documented @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface RateLimiter {   /**  * 类型(DEFAULT:全局限流;IP:IP 全局限流;CLUSTER:集群模式单实例限流)  */  LimitType type() default LimitType.DEFAULT;   /**  * 名称  */  String name() default "";   /**  * 键(支持 Spring EL 表达式)  */  String key() default "";   /**  * 速率(指定时间间隔产生的令牌数)  */  int rate() default Integer.MAX_VALUE;   /**  * 速率间隔(时间间隔)  */  int interval() default 0;   /**  * 速率间隔时间单位(默认:毫秒)  */  TimeUnit unit() default TimeUnit.MILLISECONDS;   /**  * 提示信息  */  String message() default "操作过于频繁,请稍后再试"; }

RateLimiterNameGenerator 接口

RateLimiterNameGenerator 是限流器名称生成器接口,当 @RateLimiter 注解的 name 属性为空时用于生成限流器名称。

RateLimiterNameGenerator
java
public interface RateLimiterNameGenerator {   /**  * Generate a rate limiter name for the given method and its parameters.  *  * @param target the target instance  * @param method the method being called  * @param args the method parameters (with any var-args expanded)  * @return a generated rate limiter name  */  String generate(Object target, Method method, Object... args); }

默认已经提供了 DefaultRateLimiterNameGenerator 实现(根据方法名、方法参数等生成限流器名称),如果不满足你的需要,可自行重写 RateLimiterNameGenerator 接口来实现自定义限流器名称生成器,然后在 Spring 容器中提供 RateLimiterNameGenerator Bean 即可。

java
@Configuration public class GlobalConfiguration {   /**  * 限流器名称生成器  */  @Bean  public RateLimiterNameGenerator nameGenerator() {  return new MyRateLimiterNameGenerator();  } }

核心依赖

依赖描述
top.continew.starter:continew-starter-cache-redisson缓存模块
top.continew.starter:continew-starter-webWeb 模块

参考资料

1.Redisson 官网-RateLimiter:https://redisson.pro/docs/data-and-services/objects/#ratelimiter