使用 Spring Boot 实现限流功能:从理论到实践

简介: 【6月更文挑战第18天】在微服务和高并发系统中,限流(Rate Limiting)是一种非常重要的技术手段,用于保护系统免受过载,确保服务的稳定性。限流可以控制请求的速率,防止单个客户端或恶意用户消耗过多的资源,从而影响其他用户。

在微服务和高并发系统中,限流(Rate Limiting)是一种非常重要的技术手段,用于保护系统免受过载,确保服务的稳定性。限流可以控制请求的速率,防止单个客户端或恶意用户消耗过多的资源,从而影响其他用户。

一、限流的理论基础

常见的限流算法包括:

  1. 固定窗口计数算法(Fixed Window Counter):将时间分为固定的窗口,计数当前窗口内的请求数。
  2. 滑动窗口计数算法(Sliding Window Counter):在固定窗口计数的基础上,引入滑动窗口,细化时间粒度。
  3. 漏桶算法(Leaky Bucket):请求以恒定的速率流出,处理请求时模拟水从桶中流出。
  4. 令牌桶算法(Token Bucket):系统以恒定的速率向桶中添加令牌,请求到达时取走令牌,没有令牌则拒绝服务。

二、Spring Boot 实现限流

使用 Spring Boot 实现限流,可以通过以下几种方式:

  1. 基于过滤器(Filter)的限流实现
  2. 使用第三方库,如 Bucket4j
  3. 使用 Redis 实现分布式限流

下面我们分别介绍这些方法的实现。

方法一:基于过滤器的限流实现

1.1 创建过滤器

首先,我们创建一个限流过滤器,通过 AtomicIntegerSemaphore 来控制请求速率。

java复制代码

import org.springframework.stereotype.Component;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.Semaphore;

@Component
public class RateLimitingFilter implements Filter {

    private static final int MAX_REQUESTS_PER_SECOND = 10;
    private Semaphore semaphore = new Semaphore(MAX_REQUESTS_PER_SECOND);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        if (semaphore.tryAcquire()) {
            try {
                chain.doFilter(request, response);
            } finally {
                semaphore.release();
            }
        } else {
            ((HttpServletResponse) response).setStatus(HttpServletResponse.SC_TOO_MANY_REQUESTS);
        }
    }

    @Override
    public void destroy() {
    }
}

1.2 配置过滤器

在 Spring Boot 应用中,过滤器自动注册,只需要添加 @Component 注解即可。不过,你也可以手动配置:

java复制代码

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean<RateLimitingFilter> loggingFilter() {
        FilterRegistrationBean<RateLimitingFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new RateLimitingFilter());
        registrationBean.addUrlPatterns("/*");
        return registrationBean;
    }
}

方法二:使用 Bucket4j 实现限流

2.1 添加依赖

pom.xml 中添加 Bucket4j 依赖:

xml复制代码

<dependency>
    <groupId>com.github.vladimir-bukhtoyarov</groupId>
    <artifactId>bucket4j-core</artifactId>
    <version>6.2.0</version>
</dependency>

2.2 创建限流过滤器

java复制代码

import com.github.bucket4j.Bandwidth;
import com.github.bucket4j.Bucket;
import com.github.bucket4j.Refill;
import org.springframework.stereotype.Component;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.Duration;

@Component
public class Bucket4jRateLimitingFilter implements Filter {

    private static final int CAPACITY = 10;
    private static final int REFILL_TOKENS = 10;
    private static final Duration REFILL_DURATION = Duration.ofSeconds(1);

    private final Bucket bucket;

    public Bucket4jRateLimitingFilter() {
        Bandwidth limit = Bandwidth.classic(CAPACITY, Refill.greedy(REFILL_TOKENS, REFILL_DURATION));
        this.bucket = Bucket.builder().addLimit(limit).build();
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        if (bucket.tryConsume(1)) {
            chain.doFilter(request, response);
        } else {
            ((HttpServletResponse) response).setStatus(HttpServletResponse.SC_TOO_MANY_REQUESTS);
        }
    }

    @Override
    public void destroy() {
    }
}

2.3 配置过滤器

与方法一类似,配置过滤器即可:

java复制代码

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean<Bucket4jRateLimitingFilter> loggingFilter() {
        FilterRegistrationBean<Bucket4jRateLimitingFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new Bucket4jRateLimitingFilter());
        registrationBean.addUrlPatterns("/*");
        return registrationBean;
    }
}

方法三:使用 Redis 实现分布式限流

3.1 添加依赖

pom.xml 中添加 Redis 和 Redisson 依赖:

xml复制代码

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

3.2 配置 Redis 和 Redisson

application.properties 中配置 Redis:

properties复制代码

spring.redis.host=localhost
spring.redis.port=6379

3.3 创建 Redis 限流过滤器

java复制代码

import org.redisson.api.RRateLimiter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class RedisRateLimitingFilter implements Filter {

    @Autowired
    private RedissonClient redissonClient;

    private RRateLimiter rateLimiter;

    @Bean
    public RRateLimiter rateLimiter() {
        RRateLimiter rateLimiter = redissonClient.getRateLimiter("rateLimiter");
        rateLimiter.trySetRate(RRateType.OVERALL, 10, 1, RateIntervalUnit.SECONDS);
        return rateLimiter;
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.rateLimiter = rateLimiter();
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        if (rateLimiter.tryAcquire(1)) {
            chain.doFilter(request, response);
        } else {
            ((HttpServletResponse) response).setStatus(HttpServletResponse.SC_TOO_MANY_REQUESTS);
        }
    }

    @Override
    public void destroy() {
    }
}

3.4 配置过滤器

与之前的方法一样,配置过滤器:

java复制代码

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean<RedisRateLimitingFilter> loggingFilter() {
        FilterRegistrationBean<RedisRateLimitingFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new RedisRateLimitingFilter());
        registrationBean.addUrlPatterns("/*");
        return registrationBean;
    }
}

结论

在本指南中,我们介绍了三种在 Spring Boot 中实现限流的方法:

  1. 基于过滤器的简单限流实现。
  2. 使用第三方库 Bucket4j 实现限流。
  3. 使用 Redis 实现分布式限流。

每种方法都有其优缺点和适用场景,可以根据具体需求选择合适的方案。希望本文能帮助你在项目中实现限流功能,保障系统的稳定性和可靠性。

相关文章
|
7月前
|
安全 NoSQL Java
SpringBoot接口安全:限流、重放攻击、签名机制分析
本文介绍如何在Spring Boot中实现API安全机制,涵盖签名验证、防重放攻击和限流三大核心。通过自定义注解与拦截器,结合Redis,构建轻量级、可扩展的安全防护方案,适用于B2B接口与系统集成。
939 3
|
6月前
|
存储 人工智能 Java
AI 超级智能体全栈项目阶段四:学术分析 AI 项目 RAG 落地指南:基于 Spring AI 的本地与阿里云知识库实践
本文介绍RAG(检索增强生成)技术,结合Spring AI与本地及云知识库实现学术分析AI应用,利用阿里云Qwen-Plus模型提升回答准确性与可信度。
1907 90
AI 超级智能体全栈项目阶段四:学术分析 AI 项目 RAG 落地指南:基于 Spring AI 的本地与阿里云知识库实践
|
8月前
|
前端开发 Java API
利用 Spring WebFlux 技术打造高效非阻塞 API 的完整开发方案与实践技巧
本文介绍了如何使用Spring WebFlux构建高效、可扩展的非阻塞API,涵盖响应式编程核心概念、技术方案设计及具体实现示例,适用于高并发场景下的API开发。
601 0
|
6月前
|
人工智能 监控 Java
Spring AI Alibaba实践|后台定时Agent
基于Spring AI Alibaba框架,可构建自主运行的AI Agent,突破传统Chat模式限制,支持定时任务、事件响应与人工协同,实现数据采集、分析到决策的自动化闭环,提升企业智能化效率。
Spring AI Alibaba实践|后台定时Agent
|
6月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
669 2
|
10月前
|
算法 网络协议 Java
Spring Boot 的接口限流算法
本文介绍了高并发系统中流量控制的重要性及常见的限流算法。首先讲解了简单的计数器法,其通过设置时间窗口内的请求数限制来控制流量,但存在临界问题。接着介绍了滑动窗口算法,通过将时间窗口划分为多个格子,提高了统计精度并缓解了临界问题。随后详细描述了漏桶算法和令牌桶算法,前者以固定速率处理请求,后者允许一定程度的流量突发,更符合实际需求。最后对比了各算法的特点与适用场景,指出选择合适的算法需根据具体情况进行分析。
863 56
Spring Boot 的接口限流算法
|
8月前
|
Java 应用服务中间件 开发者
Spring Boot 技术详解与应用实践
本文档旨在全面介绍 Spring Boot 这一广泛应用于现代企业级应用开发的框架。内容将涵盖 Spring Boot 的核心概念、核心特性、项目自动生成与结构解析、基础功能实现(如 RESTful API、数据访问)、配置管理以及最终的构建与部署。通过本文档,读者将能够理解 Spring Boot 如何简化 Spring 应用的初始搭建和开发过程,并掌握其基本使用方法。
573 2
|
9月前
|
缓存 前端开发 Java
SpringBoot 实现动态菜单功能完整指南
本文介绍了一个动态菜单系统的实现方案,涵盖数据库设计、SpringBoot后端实现、Vue前端展示及权限控制等内容,适用于中后台系统的权限管理。
912 1