如果你觉得这篇文章对你有帮助,请不要吝惜你的“关注”、“点赞”、“评价”、“收藏”,你的支持永远是我前进的动力~~~
Java API接口限流:概念、实现与示例
在高并发的互联网应用中,API接口限流是一种重要的保护机制,它通过控制单位时间内的请求数量来防止系统过载,确保服务的稳定性和可用性。本文将介绍Java中API接口限流的概念、实现方式,并提供一个简单的Java示例。
1. 限流的概念
限流(Rate Limiting)是指在一定时间范围内限制请求的处理速率,以避免系统因请求过多而崩溃。限流策略可以基于不同的维度,如IP地址、用户账号、服务接口等。
2. 限流的实现方式
2.1 Guava RateLimiter
Guava库提供了一个简单而强大的限流工具RateLimiter
,它基于令牌桶算法实现。RateLimiter
可以创建一个速率限制器,用于控制某个代码段的执行速率。
集成步骤:
- 引入依赖:在Spring Boot项目中引入Guava依赖。
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>32.0.1-jre</version> </dependency>
- 创建RateLimiter实例:在服务类或控制器中创建
RateLimiter
实例。import com.google.common.util.concurrent.RateLimiter; public class RateLimiterService { private final RateLimiter rateLimiter = RateLimiter.create(5.0); // 每秒允许5个请求 public void executeLimitedService() { rateLimiter.acquire(); // 阻塞直到获取一个许可 System.out.println("执行业务逻辑"); } }
2.2 Sentinel 限流
Sentinel是阿里巴巴开源的分布式系统流量防卫组件,它提供了丰富的流量控制功能,包括QPS(每秒查询率)限制。
代码示例:
- Sentinel限流注解:
@Aspect @Component public class SentinelLimitRateAspect { @Pointcut(value = "@annotation(com.hcr.sbes.limit.sentinel.SentinelLimitRateAnnotation)") public void rateLimit() {} @Around("rateLimit()") public Object around(ProceedingJoinPoint joinPoint) { Method currentMethod = getCurrentMethod(joinPoint); String resourceName = currentMethod.getAnnotation(SentinelLimitRateAnnotation.class).resourceName(); int limitCount = currentMethod.getAnnotation(SentinelLimitRateAnnotation.class).limitCount(); initFlowRule(resourceName, limitCount); Entry entry = null; Object result = null; try { entry = SphU.entry(resourceName); result = joinPoint.proceed(); } catch (BlockException ex) { return "被限流了"; } finally { if (entry != null) { entry.exit(); } } return result; } }
- 测试接口:
@GetMapping("/limitBySentinel") @SentinelLimitRateAnnotation(resourceName = "测试限流2", limitCount = 1) public String limitBySentinel() { return "limitBySentinel"; }
2.3 Redis + Lua 限流
Redis是一个高性能的键值存储系统,结合Lua脚本可以实现分布式限流。
代码示例:
- Lua脚本:
redis.replicate_commands(); local listLen, time = redis.call('LLEN', KEYS[1]) if listLen and tonumber(listLen) < tonumber(ARGV[1]) then local a = redis.call('TIME'); redis.call('LPUSH', KEYS[1], a[1]*1000000+a[2]) else time = redis.call('LINDEX', KEYS[1], -1) local a = redis.call('TIME'); if a[1]*1000000+a[2] - time < tonumber(ARGV[2])*1000000 then return 0; else redis.call('LPUSH', KEYS[1], a[1]*1000000+a[2]) redis.call('LTRIM', KEYS[1], 0, tonumber(ARGV[1])-1) end end return 1;
- Java调用:
public Object around(ProceedingJoinPoint pjp) { MethodSignature methodSignature = (MethodSignature)pjp.getSignature(); Method method = methodSignature.getMethod(); RedisLimit annotation = method.getAnnotation(RedisLimit.class); LimitType limitType = annotation.limitType(); String name = annotation.name(); String key; int period = annotation.period(); int count = annotation.count(); // 省略获取key和调用Lua脚本的代码... }
3. 结论
API接口限流是保护后端服务不受过多请求冲击的有效手段。通过Guava的RateLimiter
、Sentinel以及Redis+Lua等技术,我们可以在Java应用中实现高效且稳定的限流策略。这些方法各有优势,可以根据具体的业务场景和需求选择合适的限流方案。