Spring Boot 实现全局 API 限频最佳实践
【摘要】 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. 应用使用场景
- 防止恶意请求: 限制单个用户或 IP 在单位时间内的请求次数。
- 保护系统资源: 防止某些高频率请求耗尽系统资源。
- 流量控制: 在高峰期对 API 请求进行限流,确保系统稳定性。
- 第三方 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 的 incr
和 expire
命令实现限频。
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. 测试步骤
- 启动 Redis 服务。
- 启动 Spring Boot 应用。
- 使用工具(如 Postman 或 JMeter)模拟高并发请求。
- 观察日志和响应,验证限频是否生效。
7. 部署场景
- 单机部署: 适用于小型应用,直接使用本地 Redis。
- 分布式部署: 适用于大型应用,使用 Redis 集群实现分布式限频。
8. 材料链接
9. 总结
基于 Spring Boot 和 Redis 的全局 API 限频是一种高效、灵活的解决方案,适用于各种规模的应用。通过拦截器或 AOP 实现限频,可以轻松集成到现有项目中。
10. 未来展望
- 动态限频: 根据系统负载动态调整限频阈值。
- 多维度限频: 支持基于用户、IP、API 等多维度的限频策略。
- AI 预测: 结合 AI 技术预测流量峰值,提前进行限频。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)