Skip to content

限流模块

最后更新: 12 天前
实践版本: v2.11.0

简介

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

主要特性

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

使用步骤

引入依赖

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

全局配置

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

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 注解

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 接口

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

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:continew-starter-cache-redisson缓存模块
top.continew:continew-starter-webWeb 模块

参考资料

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