SpringBoot通过一个注解结合Redis实现接口限流就是这么简单

接口限流是指在系统中对接口进行限制访问 , 以保护系统不被过载或异常流量所影响 。这通常是为了防止DDoS攻击或其他类型的恶意流量攻击 , 以及确保系统的稳定性和可靠性 。环境:Springboot3.0.5
概述接口限流是指在系统中对接口进行限制访问 , 以保护系统不被过载或异常流量所影响 。这通常是为了防止DDoS攻击或其他类型的恶意流量攻击 , 以及确保系统的稳定性和可靠性 。
接口限流可以采取多种方法 , 包括:

  • 计数器:记录每个接口的访问次数 , 如果超过预设的限制 , 则限制对该接口的访问 。
  • 速率限制:限制每个接口的访问速率 , 例如每秒请求数 。
  • 滑动窗口算法:记录一段时间内每个接口的访问次数 , 并根据这些数据进行限流 。
  • 漏桶算法:限制一段时间内的总访问次数或总请求数 , 无论接口是否被频繁访问 。
  • 基于流的限流:根据网络流量进行限流 , 例如限制每个IP地址的流量 。
接口限流可以保护系统免受异常流量攻击 , 但同时也可能会对正常用户造成一些影响 , 因此需要合理设置限流策略 , 以确保系统的稳定性和可靠性 。
限流实现方案Guava实现接口限流@Testpublic void testWithRateLimiter() {long start = System.currentTimeMillis() ;// 每秒最多接受10个请求RateLimiter limiter = RateLimiter.create(10.0) ;for (int i = 0; i < 10; i++) {// 如果没有可用的将会被阻塞limiter.acquire() ;System.out.println("execution bussiness invoke...") ;TimeUnit.SECONDS.sleep(1) ;}long end = System.currentTimeMillis() ;System.out.println((end - start) + "ms") ;}2. 通过Spring Cloud Gateway在Spring Cloud Gateway中提供了RequestRateLimiterGatewayFilterFactory过滤器 , 我们可以通过配置该过滤器来实现限流 , 该过滤默认提供了基于redis实现的RedisRateLimiter 。我们可以通过自定义RateLimiter实现自己的限流方案 。
spring:cloud:gateway:routes:- id: testuri: http://localhost:8082filters:- name: RequestRateLimiterargs:key-resolver: '#{@packKeyResolver}'redis-rate-limiter.replenishRate: 1redis-rate-limiter.burstCapacity: 33. Resilience4j在该库中提供了限流的支持 , 我们可以通过编程的方式也可以直接通过注解的方式实现 。
具体查看Resilience4j的官网都有介绍 。
  • 自定义
该方案就是本文要介绍实现的方案 。
自定义接口限流接下来通过一个注解结合Redis实现简单基于计数器的方法实现接口的限流 。
依赖配置
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>配置
spring:data:redis:host: localhostport: 6379password: 123123database: 12lettuce:pool:maxActive: 8maxIdle: 100minIdle: 10maxWAIt: -1
  • 自定义注解
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface AccessLimit {// 单位时间:秒long seconds() default 1;// 单位时间内限制访问次数int count() default 10 ;}
  • 拦截器
这是我们实现接口限流的核心 , 符合条件的请求都会先进过该拦截器判断是否放行 。
@Componentpublic class AccessLimitInterceptor implements HandlerInterceptor {@Resourceprivate StringRedisTemplate stringRedisTemplate ;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 只针对@Controller(RequestMAppingHandlerMapping)的接口if (handler instanceof HandlerMethod handlerMethod) {Method method = handlerMethod.getMethod() ;// 具备AccessLimit注解的才进行拦截AccessLimit accessLimit = method.getDeclaredAnnotation(AccessLimit.class) ;if (accessLimit != null) {// 获取注解配置的参数long seconds = accessLimit.seconds() ;int count = accessLimit.count() ;if (seconds > 0 && count >= 0) {String key = request.getRemoteAddr() + ":" + request.getRequestURI() ;String value = https://www.isolves.com/it/cxkf/jiagou/2023-08-21/this.stringRedisTemplate.opsForValue().get(key) ;System.out.println("当前为:" + value) ;if (value == null) {this.stringRedisTemplate.opsForValue().set(key, String.valueOf(count - 1) , seconds, TimeUnit.SECONDS) ;return true ;} else {int c = Integer.valueOf(value) ;if (c


推荐阅读