RedisLimiter 限流器
/**
* 专门提供 RedisLimiter 限流基础服务的(提供了通用的能力)
*/
@Service
public class RedisLimiterManager {
@Resource
private RedissonClient redissonClient;
/**
* 限流操作
*
* @param key 区分不同的限流器,比如不同的用户 id 应该分别统计
*/
public void doRateLimit(String key) {
// 创建一个名称为user_limiter的限流器,每秒最多访问 2 次
RRateLimiter rateLimiter = redissonClient.getRateLimiter(key);
rateLimiter.trySetRate(RateType.OVERALL, 2, 1, RateIntervalUnit.SECONDS);
// 每当一个操作来了后,请求一个令牌
boolean canOp = rateLimiter.tryAcquire(1);
if (!canOp) {
throw new BusinessException(ErrorCode.TOO_MANY_REQUEST);
}
}
}
这段代码是Spring Boot项目中基于Redis和Redisson实现的分布式限流服务,用于控制接口或资源的访问频率,防止系统过载。以下是对其生产应用的详细解释:
核心机制
-
分布式限流:
- 使用Redisson的
RRateLimiter
实现分布式限流,确保多实例环境下限流规则全局生效。 - 依赖Redis作为中心存储,保证各服务实例的限流状态同步。
- 使用Redisson的
-
限流规则配置:
trySetRate(RateType.OVERALL, 2, 1, RateIntervalUnit.SECONDS)
设置每秒最多2次请求(令牌桶模式)。RateType.OVERALL
表示所有实例共享同一限流计数器(若需单实例限流可改为PER_CLIENT
)。
-
令牌获取:
tryAcquire(1)
尝试获取1个令牌,成功返回true
,否则false
。- 失败时抛出业务异常(如
TOO_MANY_REQUEST
),由全局异常处理器转换为HTTP 429状态码。
生产应用场景
-
高频接口防护:
- 案例:用户登录接口限制每秒2次,防止密码暴力破解。
- 代码示例:
@PostMapping("/login") public Response login(@RequestBody User user) { redisLimiterManager.doRateLimit("login_" + user.getUsername()); // 后续登录逻辑 }
-
资源保护:
- 案例:短信发送接口限制每个用户每日10次,防止短信轰炸。
- 代码示例:
public void sendSms(String phone) { String key = "sms_limit_" + phone; redisLimiterManager.doRateLimit(key); // 调用短信服务 }
-
爬虫流量管控:
- 案例:公开API按IP限制请求频率,防止爬虫过度抓取。
- 代码示例:
@GetMapping("/data") public Response getData(HttpServletRequest request) { String ip = request.getRemoteAddr(); redisLimiterManager.doRateLimit("api_ip_" + ip); // 返回数据 }
关键配置说明
参数 | 说明 | 示例值 |
---|---|---|
key | 限流维度标识 | user_123 (按用户)、api_login (按接口) |
RateType.OVERALL | 限流作用域(全局/单实例) | OVERALL (跨实例共享计数器) |
2, 1, SECONDS | 令牌生成速率 | 每秒2次 |
注意事项
-
Redis高可用:
- 若Redis宕机,限流功能失效。建议配置Redis哨兵或集群,并设计降级策略(如本地限流)。
-
Key设计规范:
- 避免Key冲突:按业务命名(如
order_limit:user_123
)。 - 防止热点Key:分散Key粒度(如按用户、IP、接口组合)。
- 避免Key冲突:按业务命名(如
-
性能影响:
- 每次限流检查需访问Redis,建议压测确认延迟(通常Redisson优化良好,单次操作约1~2ms)。
-
动态配置:
- 硬编码的限流参数(如2次/秒)可改为从配置中心(如Nacos)读取,实现动态调整。
潜在优化
-
失败降级:
boolean canOp = rateLimiter.tryAcquire(1); if (!canOp) { // 可选:触发降级逻辑(如返回默认值) throw new BusinessException(ErrorCode.TOO_MANY_REQUEST); }
-
预热机制:
rateLimiter.trySetRate(RateType.OVERALL, 10, 5, RateIntervalUnit.MINUTES); // 5分钟内均匀生成10个令牌,避免突发流量被拒
-
监控告警:
- 记录限流触发日志,监控异常请求比例,超过阈值时通知运维。
总结
该限流器通过Redis实现分布式流量控制,适用于需要精准控制请求频率的生产场景。开发者需结合业务需求设计合理的Key和限流规则,同时关注Redis稳定性与性能影响,必要时补充降级策略和监控。