限流保护机制
引用文件
本文引用的文件
- RateLimiter.java
- RateLimiterAspect.java
- YudaoRateLimiterConfiguration.java
- RateLimiterRedisDAO.java
- RateLimiterKeyResolver.java
- DefaultRateLimiterKeyResolver.java
- UserRateLimiterKeyResolver.java
- ClientIpRateLimiterKeyResolver.java
- ServerNodeRateLimiterKeyResolver.java
- ExpressionRateLimiterKeyResolver.java
- RedisUtils.java
- yudao-spring-boot-starter-protection/pom.xml
目录
简介
本文件面向 yudao-cloud 的限流保护机制,系统性阐述基于 Redisson 的分布式限流实现,覆盖以下内容:
- 限流算法与策略:基于 Redisson 的令牌桶模型与滑动窗口思想的组合实践
- RateLimiter 注解的使用与配置:限流阈值、时间窗口、拒绝策略与键空间粒度
- 高并发性能优化:本地缓存、异步处理与批量限流思路
- 监控与调优:指标采集、可视化与参数调优建议
项目结构
yudao-cloud 的限流能力位于 yudao-spring-boot-starter-protection 模块中,采用注解 + AOP + Redisson 的组合方式:
- 注解层:定义限流注解与可选键解析器
- AOP 层:拦截标注方法,计算限流键并执行限流判断
- 数据访问层:封装 Redisson RRateLimiter 的统一 DAO
- 配置层:装配切面、DAO 与多种键解析器 Bean
图表来源
- YudaoRateLimiterConfiguration.java
- RateLimiterAspect.java
- RateLimiterRedisDAO.java
- RateLimiterKeyResolver.java
章节来源
核心组件
- RateLimiter 注解:定义限流的时间窗口、阈值、提示消息、键解析器与自定义键表达式
- RateLimiterAspect:基于 AOP 在方法执行前进行限流判断
- RateLimiterRedisDAO:封装 Redisson RRateLimiter 的 tryAcquire 与动态速率配置
- RateLimiterKeyResolver 及其实现:提供多粒度的限流键生成策略
- YudaoRateLimiterConfiguration:装配切面、DAO 与各键解析器 Bean
章节来源
- RateLimiter.java
- RateLimiterAspect.java
- RateLimiterRedisDAO.java
- RateLimiterKeyResolver.java
- YudaoRateLimiterConfiguration.java
架构总览
下图展示从方法调用到限流决策的关键流程。
图表来源
详细组件分析
注解与配置参数
- time/timeUnit:时间窗口长度与单位,默认 1 秒
- count:时间窗口内的最大请求数
- message:限流时的提示消息,默认使用统一错误码
- keyResolver:选择键解析器类型,默认全局级别
- keyArg:当使用表达式键解析器时,用于指定 SpEL 表达式
章节来源
键解析器体系
- 默认键解析器:以方法签名与参数拼接后做摘要,形成全局级限流键
- 用户键解析器:在默认键基础上附加登录用户标识,形成用户级限流
- IP 键解析器:在默认键基础上附加客户端 IP,形成 IP 级限流
- 服务器节点键解析器:在默认键基础上附加主机与进程信息,形成节点级限流
- 表达式键解析器:通过 SpEL 动态解析参数,形成灵活的自定义限流键
图表来源
- RateLimiterKeyResolver.java
- DefaultRateLimiterKeyResolver.java
- UserRateLimiterKeyResolver.java
- ClientIpRateLimiterKeyResolver.java
- ServerNodeRateLimiterKeyResolver.java
- ExpressionRateLimiterKeyResolver.java
章节来源
- DefaultRateLimiterKeyResolver.java
- UserRateLimiterKeyResolver.java
- ClientIpRateLimiterKeyResolver.java
- ServerNodeRateLimiterKeyResolver.java
- ExpressionRateLimiterKeyResolver.java
限流算法与策略
- 算法基础:基于 Redisson 的 RRateLimiter,其内部采用令牌桶模型,支持 OVERALL 类型的全局速率控制
- 窗口与配额:通过 trySetRate 设置每 N 秒允许 count 个请求;每次 tryAcquire 消耗 1 个令牌
- 动态配置:若限流器已存在且配置一致则复用,否则更新配置并设置过期时间
图表来源
章节来源
AOP 切面 与拒绝策略
- 切入点:拦截带有 @RateLimiter 的方法
- 执行顺序:先解析键,再调用 DAO 执行限流,最后根据结果决定放行或抛出限流异常
- 拒绝策略:当 tryAcquire 返回 false 时,抛出统一的限流错误码与可选提示消息
图表来源
章节来源
配置与装配
- 自动装配:在 Redis 自动配置之后注册切面、DAO 与各键解析器 Bean
- 依赖注入:切面依赖键解析器集合与 DAO;DAO 依赖 RedissonClient
章节来源
与通用 Redis 工具的关系
- RedisUtils 提供更底层的 rateLimiter 封装,便于在非注解场景快速使用
- 两者共享相同的 Redisson RRateLimiter 能力,但注解模式更易用、可扩展性强
章节来源
依赖关系分析
- 组件耦合:切面依赖 DAO 与键解析器;DAO 依赖 RedissonClient
- 外部依赖:yudao-spring-boot-starter-redis 与 lock4j-redisson-spring-boot-starter(可选)
- 自动装配顺序:确保 Redis 自动配置先于限流配置完成
图表来源
章节来源
性能考虑
- 本地缓存与配置复用
- DAO 在首次创建限流器后会缓存配置,后续命中相同配置直接复用,避免重复设置
- 限流器按时间窗口过期,减少长期占用
- 异步处理
- 对于非关键路径的限流,可在业务侧结合异步任务或消息队列削峰填谷
- 批量限流
- 对批量接口建议使用更粗粒度的键(如用户级或 IP 级),并在网关层配合限流
- Redis 性能
- 合理设置过期时间与键空间,避免内存膨胀
- 使用 Redis 集群时注意键分布与热点问题
章节来源
故障排查指南
- 未生效
- 确认方法上正确标注 @RateLimiter
- 检查自动装配顺序:Redis 自动配置需先于限流配置
- 限流键不正确
- 核对 keyResolver 与 keyArg 的选择是否符合预期
- 表达式键解析器需确保 SpEL 表达式能正确解析到目标参数
- 频繁拒绝
- 调整 time 与 count,增大时间窗口或提升阈值
- 评估键粒度过细导致的误伤,必要时提升到用户级或节点级
- 异常处理
- 切面在拒绝时抛出统一限流错误码,可通过全局异常处理器统一返回
章节来源
结论
yudao-cloud 的限流保护机制以注解 + AOP + Redisson 为核心,提供了灵活的键空间粒度与简洁的配置方式。通过合理的键策略、参数调优与配套的异步/批量手段,可在高并发场景下有效保护系统稳定性与用户体验。
附录
使用示例与最佳实践
- 全局限流:适用于通用接口,使用默认键解析器
- 用户限流:针对登录用户,避免同一用户滥用
- IP 限流:适用于匿名接口,抵御刷量
- 节点限流: 适用于网关或服务节点级限流
- 自定义键:使用表达式键解析器,按业务维度灵活组合
章节来源