Spring Boot使用Redisson实现滑动窗口限流的项目实践

 更新时间:2024年03月03日 10:59:24   作者:冥胖胖9  
滑动窗口限流是一种流量控制策略,用于控制在一定时间内的请求频率,本文主要介绍了Spring Boot使用Redisson实现滑动窗口限流的项目实践,具有一定的参考价值,感兴趣的可以了解一下

一、背景

在一些业务场景中,我们可能会提供一些API接口来给用户使用,这些接口是不需要认证的。比如:忘记密码,重置密码的接口,这些接口用户可以随意调用。为了防止这些接口被攻击者恶意频繁调用,消耗我们的系统资源,通常我们会对这些接口做限流保护,否则可能会导致我们的服务器的宕机。

其实限流可以认为是服务降级的一种,限流通过限制请求的流量以达到保护系统的目的。今天我们一起来讨论一下在Redis缓存中怎么通过Redisson实现滑动窗口限流。

二、滑动窗口限流算法

1. 原理

我们先来了解一下滑动窗口限流的实现原理,话不多说,先上图。

从上图我们可以得知,有一个时间窗口随着时间轴在向右移动,我们可以记录这个时间窗口内的请求次数,当超过我们允许的阈值时,则进行限流不能继续进行请求。

2. 具体实现步骤

主要实现步骤如下:

  • 我们需要定义一个时间窗口,例如窗口大小为1分钟。
  • 每次有请求时,使用redis中的zset将这条请求记录下来。                                                     充分利用zset这个数据结果的特点,zet一条记录由两个成员(score和member)来表示,并且会按照score进行排序。方便我们后面进行删除滑动后窗口之前的请求记录,和统计当前窗口内请求总数。
  • 通过ZREMRANGEBYSCORE命令,删除zset中当前窗口之前的请求记录。
  • 通过ZCARD命令,统计当前窗口内的请求数量。

所以,我们使用滑动窗口的思想是,只保留当前时间窗口类的请求记录,而丢弃当前窗口之外的记录。当下次有请求进来时,我们只需要判断当前窗口内的请求是否超过阈值就可以了。未超过则放行,超过则限流。

3. 伪代码

根据以上步骤我们写了一段伪代码,如果考虑并发场景则需要考虑使用Lua脚本。

   public boolean allowRequest(String requestKey) {
        // 定义一个时间窗口为1分钟
        long windowSize = Duration.ofMinutes(1).toSeconds();

        // 定义时间窗口内请求阈值为100
        long limit = 100;

        // 当前时间戳
        long currentTime = System.currentTimeMillis();

        // 窗口开始时间为当前时间戳 - 窗口大小
        long windowStart = currentTime - windowSize * 1000;

        // 删除当前窗口开始之前的所有数据
        Jedis.zremrangeByScore(requestKey, "0", String.valueOf(windowStart));

        // 计算当前窗口内的请求总数
        long count = Jedis.zcard(requestKey);

        if (count < limit) {
            // 如果允许访问,则将当前请求加到窗口内
            Jedis.zadd(requestKey, currentTime, String.valueOf(currentTime));
            return true;
        }
        return false;
    }
}

三、怎么使用Redisson进行滑动窗口限流

在redisson中已经为我们实现好了滑动窗口限流,通过redissonClient拿到限流器后,配置好时间窗口和限流速率就能直接使用了。实现原理和上面我们的伪代码是一样的,只是它将这一部分封装好了,我们拿到后开箱即用。直接上代码:

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.redisson.api.RRateLimiter;
import org.redisson.api.RateIntervalUnit;
import org.redisson.api.RateType;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.filter.OncePerRequestFilter;

public class RateLimiterFilter extends OncePerRequestFilter {

    private final Logger log = LoggerFactory.getLogger(RateLimiterFilter.class);

    private static final String RATE_LIMIT_KEY = "rateLimit:yourApiKey";
    private static final int MAX_REQUESTS_PER_MINUTE = 10;

    private final RedissonClient redissonClient;

    public RateLimiterFilter(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }
    
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {
        RRateLimiter rateLimiter = redissonClient.getRateLimiter(RATE_LIMIT_KEY);
        // rateLimiter.trySetRate就是设置限流参数,RateType有两种,OVERALL是全局限流 ,PER_CLIENT是单Client限流(可以认为就是单机限流),这里我们只讨论全局模式。
        // 而后面三个参数的作用就是设置在多长时间窗口内(rateInterval+IntervalUnit),许可总量不超过多少(rate)
        // 上面代码中我设置的值就是1分钟内总许可数不超过10个
        rateLimiter.trySetRate(RateType.OVERALL, MAX_REQUESTS_PER_MINUTE, 1, RateIntervalUnit.MINUTES);
        // 调用rateLimiter的tryAcquire()或者acquire()方法即可获取许可
        if (!rateLimiter.tryAcquire()) {
            
            String path = request.getRequestURI().substring(request.getContextPath().length());
            log.error("当前请求触发限流策略,请求: {} 已经被限流.", path);

            response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
            response.getWriter().write("Too many requests!");
            return;
        }
        filterChain.doFilter(request, response);
    }
}

四、滑动窗口限流的优势

滑动窗口限流是一种流量控制策略,用于控制在一定时间内的请求频率。它的主要优点是可以在单位时间内平滑的控制流量,而不是简单的设置固定的请求数或速率。这使得系统可以更灵活的应对突发流量或峰值流量,而不会因为固定速率的限制而浪费或降低系统性能。

这种限流算法可以在分布式系统、API服务等各种场景中使用,以确保系统的稳定性和可用性,防止过多的请求或恶意请求对系统造成负担或崩溃。

到此这篇关于Spring Boot使用Redisson实现滑动窗口限流的项目实践的文章就介绍到这了,更多相关SpringBoot Redisson滑动窗口限流内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解Nacos中注册中心和配置中心的实现

    详解Nacos中注册中心和配置中心的实现

    Spring Cloud Alibaba 是阿里巴巴提供的一站式微服务开发解决方案。而 Nacos 作为 Spring Cloud Alibaba 的核心组件之一,提供了两个非常重要的功能:注册中心和配置中心,我们今天来了解和实现一下二者
    2022-08-08
  • Quartz中的Job与JobDetail解析

    Quartz中的Job与JobDetail解析

    这篇文章主要介绍了Quartz中的Job与JobDetail解析,你定义了一个实现Job接口的类,这个类仅仅表明该job需要完成什么类型的任务,除此之外,Quartz还需要知道该Job实例所包含的属性;这将由JobDetail类来完成,需要的朋友可以参考下
    2023-11-11
  • Spring中@Transactional注解的使用详解

    Spring中@Transactional注解的使用详解

    @Transactional注解是Spring提供的一种声明式事务管理方式,这篇文章主要为大家详细介绍了@Transactional注解的原理分析及使用,需要的可以参考一下
    2023-05-05
  • SpringBoot+Echarts实现请求后台数据显示饼状图

    SpringBoot+Echarts实现请求后台数据显示饼状图

    这篇文章主要介绍了SpringBoot+Echarts实现请求后台数据显示饼状图,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-12-12
  • 数据库阿里连接池 druid配置详解

    数据库阿里连接池 druid配置详解

    本篇文章主要介绍了数据库阿里连接池 druid配置详解,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-05-05
  • Java利用异常中断当前任务的技巧分享

    Java利用异常中断当前任务的技巧分享

    在日常开发中,我们经常遇到调用别人的代码来完成某个任务,但是当代码比较耗时的时候,没法从外部终止该任务,所以本文为大家介绍了如何利用异常中断当前任务,需要的可以参考下
    2023-08-08
  • 一款不可错过的Java应用诊断利器Arthas

    一款不可错过的Java应用诊断利器Arthas

    Arthas是一款由阿里巴巴开源的Java应用诊断利器,它可以帮助开发人员在运行时对Java应用进行调试和诊断,解决线上问题,本文将简单的描述一下该工具的用法和常用命令,以勾起大家对此工具应用的兴趣
    2023-06-06
  • MyBatis之一级缓存和二级缓存问题

    MyBatis之一级缓存和二级缓存问题

    这篇文章主要介绍了MyBatis之一级缓存和二级缓存问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • Spring boot配置绑定和配置属性校验的方式详解

    Spring boot配置绑定和配置属性校验的方式详解

    这篇文章主要介绍了Spring boot配置绑定和配置属性校验,SpringBoot 提供了2 种方式进行配置绑定,即使用 @ConfigurationProperties 注解和使用 @Value 注解,需要的朋友可以参考下
    2022-05-05
  • Spring MVC 中 AJAX请求并返回JSON的示例

    Spring MVC 中 AJAX请求并返回JSON的示例

    本篇文章主要介绍了Spring MVC 中 AJAX请求并返回JSON,具有一定的参考价值,有兴趣的可以了解一下。
    2017-01-01

最新评论