Spring Boot 实现全局 API 限频最佳实践

举报
鱼弦 发表于 2025/02/11 09:29:53 2025/02/11
【摘要】 Spring Boot 实现全局 API 限频最佳实践 1. 介绍在高并发场景下,API 限频(Rate Limiting)是保护系统免受恶意请求或过载的重要手段。Spring Boot 提供了多种方式实现 API 限频,包括基于过滤器、拦截器、AOP 以及第三方库(如 Guava、Redis)等。本文将介绍如何基于 Spring Boot + Redis 实现全局 API 限频。 2. ...

Spring Boot 实现全局 API 限频最佳实践

1. 介绍

在高并发场景下,API 限频(Rate Limiting)是保护系统免受恶意请求或过载的重要手段。Spring Boot 提供了多种方式实现 API 限频,包括基于过滤器、拦截器、AOP 以及第三方库(如 Guava、Redis)等。本文将介绍如何基于 Spring Boot + Redis 实现全局 API 限频。


2. 应用使用场景

  1. 防止恶意请求: 限制单个用户或 IP 在单位时间内的请求次数。
  2. 保护系统资源: 防止某些高频率请求耗尽系统资源。
  3. 流量控制: 在高峰期对 API 请求进行限流,确保系统稳定性。
  4. 第三方 API 调用: 限制对第三方 API 的调用频率,避免超出配额。

3. 不同场景下的详细代码实现

场景 1: 基于 Redis 的全局 API 限频

依赖配置:
pom.xml 中添加 Redis 和 Spring Boot Web 依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

Redis 配置:
application.yml 中配置 Redis 连接:

spring:
  redis:
    host: localhost
    port: 6379

限频逻辑实现:
使用 Redis 的 increxpire 命令实现限频。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;

@Component
public class RateLimiter {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 检查是否允许请求
     *
     * @param key      限频键(如用户ID或IP)
     * @param limit    单位时间内的最大请求数
     * @param interval 单位时间(秒)
     * @return 是否允许请求
     */
    public boolean allowRequest(String key, int limit, int interval) {
        String redisKey = "rate_limit:" + key;
        Long currentCount = redisTemplate.opsForValue().increment(redisKey, 1);
        if (currentCount == 1) {
            redisTemplate.expire(redisKey, interval, TimeUnit.SECONDS);
        }
        return currentCount != null && currentCount <= limit;
    }
}

全局拦截器:
使用 Spring Boot 的拦截器实现全局限频。

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;

@Component
public class RateLimitInterceptor implements HandlerInterceptor {

    @Autowired
    private RateLimiter rateLimiter;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String ip = request.getRemoteAddr(); // 获取客户端IP
        int limit = 10; // 单位时间内最大请求数
        int interval = 60; // 单位时间(秒)

        if (!rateLimiter.allowRequest(ip, limit, interval)) {
            response.setStatus(429); // 返回 429 Too Many Requests
            response.getWriter().write("Rate limit exceeded. Try again later.");
            return false;
        }
        return true;
    }
}

注册拦截器:
将拦截器注册到 Spring Boot 中。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private RateLimitInterceptor rateLimitInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(rateLimitInterceptor).addPathPatterns("/api/**");
    }
}

场景 2: 基于 AOP 的 API 限频

如果需要对特定方法进行限频,可以使用 AOP 实现。

AOP 实现:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class RateLimitAspect {

    @Autowired
    private RateLimiter rateLimiter;

    @Before("@annotation(rateLimit)")
    public void before(RateLimit rateLimit) {
        String key = "method_limit:" + rateLimit.key();
        if (!rateLimiter.allowRequest(key, rateLimit.limit(), rateLimit.interval())) {
            throw new RuntimeException("Rate limit exceeded");
        }
    }
}

自定义注解:
定义一个注解用于标记需要限频的方法。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimit {
    String key() default "default";
    int limit() default 10;
    int interval() default 60;
}

使用注解:
在需要限频的方法上添加注解。

@RestController
public class ApiController {

    @RateLimit(key = "myApi", limit = 5, interval = 30)
    @GetMapping("/api/resource")
    public String getResource() {
        return "Resource data";
    }
}

4. 原理解释

算法原理

  • 计数器算法: 使用 Redis 的 incr 命令记录请求次数,并通过 expire 设置过期时间。
  • 滑动窗口: 通过 Redis 的 zset 数据结构实现更精确的限频。

流程图

请求 -> 拦截器/AOP -> 检查 Redis 计数器 -> 允许/拒绝请求

5. 实际详细应用代码示例实现

场景 1场景 2 的代码实现。


6. 测试步骤

  1. 启动 Redis 服务。
  2. 启动 Spring Boot 应用。
  3. 使用工具(如 Postman 或 JMeter)模拟高并发请求。
  4. 观察日志和响应,验证限频是否生效。

7. 部署场景

  • 单机部署: 适用于小型应用,直接使用本地 Redis。
  • 分布式部署: 适用于大型应用,使用 Redis 集群实现分布式限频。

8. 材料链接


9. 总结

基于 Spring Boot 和 Redis 的全局 API 限频是一种高效、灵活的解决方案,适用于各种规模的应用。通过拦截器或 AOP 实现限频,可以轻松集成到现有项目中。


10. 未来展望

  • 动态限频: 根据系统负载动态调整限频阈值。
  • 多维度限频: 支持基于用户、IP、API 等多维度的限频策略。
  • AI 预测: 结合 AI 技术预测流量峰值,提前进行限频。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。