当前位置: 首页 > news >正文

java Redisson 实现限流每秒/分钟/小时限制N个请求 -V2.0

概述

在先前的版本中,推出了基于 Java Redisson 的限流功能,可实现每秒/分钟/小时限制 N 个请求。然而,在实际生产环境中,我们发现了一个问题:当修改限流配置后,部分旧用户未能即时采用新的限流规则,而新用户则顺利应用了新规则。这导致了用户体验的不一致以及潜在的流量控制风险。

为了解决这一问题,对限流功能进行了全面优化,推出了第二版。在新版本中,限流规则的修改能够实时生效,无论是新用户还是旧用户,都将立即遵循最新的限流策略。这一改进确保了流量控制的准确性和一致性,为系统的稳定运行提供了更有力的保障。

旧版本链接:
https://blog.csdn.net/hyc123123123123/article/details/144849939?spm=1011.2124.3001.6209

1.引入maven包:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.23.3</version>
</dependency>    

2.配置文件

rate-limiter:# 是否启用限流user-rate-limiter-run: true# 限流拦截器 限制多少个请求user-rate-limiter-number: 30# 限流拦截器时间范围(秒)user-rate-limiter-time: 10

3.配置类


import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;/*** @Description 限流配置文件* @Author hanyc* @Date 20250912*/
@Data
@Configuration
@ConfigurationProperties(prefix = "rate-limiter")
public class RateLimiterProperties {/*** 限流拦截器10秒限制多少个请求.*/private long userRateLimiterNumber;/*** 限流拦截器 N秒 限制多少个请求.*/private long userRateLimiterTime;/*** 是否启用限流*/private Boolean userRateLimiterRun;
}

4.代码实现:

a.RedissonConfig 初始化

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** redisson** @author hanyc* @date 2025/09/12 13:30*/
@Configuration
public class RedissonConfig {@Autowiredprivate RedisProperties redisProperties;@Beanpublic RedissonClient redissonClient() {Config config = new Config();String address = "redis://" + redisProperties.getHost() + ":" + redisProperties.getPort();config.useSingleServer().setKeepAlive(true).setAddress(address).setPassword(redisProperties.getPassword())// 2秒心跳,保证链接可用性.setPingConnectionInterval(2000);RedissonClient redisson = Redisson.create(config);return redisson;}
}

b.UserRateLimiterInterceptor  用户请求限流拦截器


import cn.hutool.extra.servlet.ServletUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import java.util.concurrent.TimeUnit;/*** @Description: 用户请求限流拦截器* @Author hanyc* @Date 2025/09/12**/
@Component
@Slf4j
public class UserRateLimiterInterceptor implements HandlerInterceptor {@Autowiredprivate ScientificPermitAllUrlProperties scientificPermitAllUrlProperties;@Autowiredprivate RedissonClient redissonClient;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 替换为自定义获取用户id方法Long userId = 1L;if (!scientificPermitAllUrlProperties.getUserRateLimiterRun()) {// 不需要限流.return true;}// 假设这个方法能够从请求中解析出用户IDString userIdStr = "";String userIp = ServletUtil.getClientIP(request);if (userId == null) {// 所有未登录账号 不需要验证的请求,都使用userId=10000userIdStr = userIp;} else {userIdStr = userId.toString();}// 为每个用户生成唯一的限流键String rateLimiterKey = USER_RATE_LIMITER + userIdStr;// 获取分布式的 RRateLimiter 实例RRateLimiter rateLimiter = getRedissonRateLimiter(rateLimiterKey);log.debug("当前路由为:{} userIdStr:{} userIp:{}", request.getRequestURI(), userIdStr, userIp);// 尝试获取令牌,如果获取不到说明超过请求限制if (rateLimiter.tryAcquire()) {// 允许继续处理请求return true;} else {// 如果获取不到令牌,则说明请求超过了限制,可以在这里抛出异常或者返回错误信息log.warn("当前多余的路由为:{} userIdStr:{} userIp :{}", request.getRequestURI(), userIdStr, userIp);throw new ScientificBusinessException("访问过于频繁,请稍后重试");}}/*** 获取Redisson的RRateLimiter** @param key KEY* @return*/private RRateLimiter getRedissonRateLimiter(String key) {// 限流次数,注意count的值不能小于1,必须大于等于1long count = scientificPermitAllUrlProperties.getUserRateLimiterNumber();// 限流时间 秒long timeOut = scientificPermitAllUrlProperties.getUserRateLimiterTime();RRateLimiter rateLimiter = redissonClient.getRateLimiter(key);// 如果限流器不存在,就创建一个RRateLimiter限流器if (!rateLimiter.isExists()) {rateLimiter.trySetRate(RateType.OVERALL, count, timeOut, RateIntervalUnit.SECONDS);return rateLimiter;}// 获取限流的配置信息RateLimiterConfig rateLimiterConfig = rateLimiter.getConfig();// 上次配置的限流时间毫秒值Long rateInterval = rateLimiterConfig.getRateInterval();// 上次配置的限流次数Long rate = rateLimiterConfig.getRate();// 将timeOut转换成毫秒之后再跟rateInterval进行比较if (TimeUnit.MILLISECONDS.convert(timeOut, TimeUnit.SECONDS) != rateInterval || count != rate) {// 如果rateLimiterConfig的配置跟我们注解上面的值不一致,说明服务器重启过,程序员又修改了限流的配置// 删除原有配置rateLimiter.delete();// 以程序员重启后的限流配置为准,重新设置rateLimiter.trySetRate(RateType.OVERALL, count, timeOut, RateIntervalUnit.SECONDS);}return rateLimiter;}
}

c. WebMvcConfig 添加自定义拦截器

package com.hanyc.demo.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/*** MVC自定义配置** @author hanyc*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Beanpublic UserRateLimiterInterceptor userRateLimiterInterceptor() {return new UserRateLimiterInterceptor();}@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(userRateLimiterInterceptor()).addPathPatterns("/**");}
}


    文章转载自:

    http://6PJjXQFC.pxLqL.cn
    http://eo5f9XDc.pxLqL.cn
    http://zrKyGJGo.pxLqL.cn
    http://6l2o6Caj.pxLqL.cn
    http://kHIroC8U.pxLqL.cn
    http://9Gl84Dtx.pxLqL.cn
    http://G2nsABb3.pxLqL.cn
    http://EIp75ddh.pxLqL.cn
    http://q6UOM3o8.pxLqL.cn
    http://JQUOvmFn.pxLqL.cn
    http://k88IpNJL.pxLqL.cn
    http://nK3JPsVE.pxLqL.cn
    http://OQv8Ekl5.pxLqL.cn
    http://f8BZeTz2.pxLqL.cn
    http://SB91VlQC.pxLqL.cn
    http://Lglk79w4.pxLqL.cn
    http://hOvR2n63.pxLqL.cn
    http://JRw1bAhT.pxLqL.cn
    http://bAjufdHi.pxLqL.cn
    http://A9BB0pmg.pxLqL.cn
    http://O3EQJI1q.pxLqL.cn
    http://ZscQFsGv.pxLqL.cn
    http://FQuPLYi1.pxLqL.cn
    http://RDXeAVhg.pxLqL.cn
    http://2Kn1y4xB.pxLqL.cn
    http://n4vX50Gt.pxLqL.cn
    http://FBsNQgTX.pxLqL.cn
    http://5YdKC14C.pxLqL.cn
    http://0yoyvKNG.pxLqL.cn
    http://hJ7H7kRN.pxLqL.cn
    http://www.dtcms.com/a/379659.html

    相关文章:

  1. 高并发、低延迟全球直播系统架构
  2. zookeeper是啥
  3. 短波红外相机在机器视觉检测方向的应用
  4. 阿里云国际代理:如何利用RDS构建高可用、可扩展的数据库架构
  5. 【Python】通俗理解反向传播
  6. RFID技术在半导体电子货架上的应用方案
  7. Windows 安装 Redis 教程
  8. CMake 全流程开发实战:从零开始掌握C++项目构建、测试到一键分发的完整解决方案​
  9. 如果数据量小但是点击后需要获取的是最新的定位信息,这种时候采取什么策略最优?
  10. 使用 Pyinstaller 打包 PPOCRLabel
  11. 科技信息差(9.12)
  12. 是德科技 | 关于AI 数据中心时代的光通信的精选问答
  13. 深入剖析 Elasticsearch (ES) 的近实时搜索原理
  14. Qt5 | TCP服务器开源模板工程实战
  15. 飞鹤财报“新解”:科技筑牢护城河,寒冬凸显龙头“硬核力”
  16. 第6.2节 Android Agent开发<一>
  17. 【 C/C++ 算法】入门动态规划-----一维动态规划基础(以练代学式)
  18. YOLOv8 从yaml配置文件生成PyTorch模型
  19. 重复文件清理的标准化操作流程
  20. Amazon DocumentDB Serverless 技术深度解析:架构特性、弹性扩缩容机制与实操指南
  21. 项目管理方法适合什么类型的企业
  22. HTTPS(Hypertext Transfer Protocol Secure,超文本传输安全协议)
  23. 【LLM越狱】AI大模型DRA攻击解读与复现
  24. k8s下的发布策略详解
  25. 第 9 篇:深入浅出学 Java 语言(JDK8 版)—— 吃透泛型机制,筑牢 Java 类型安全防线
  26. 机器人防爆与隔爆的本质,两者的区别对比
  27. 从蛮力清扫到 “会看路”:室外清洁机器人的文明进阶
  28. 大数据毕业设计选题推荐-基于大数据的家庭能源消耗数据分析与可视化系统-Hadoop-Spark-数据可视化-BigData
  29. 【Settings】恢复出厂设置密码校验
  30. 机器人控制器开发(通讯——ros话题转为websocket)