本文目录导读:

在Java中实现接口限流,常见的方案有单机限流和分布式限流,下面分别介绍几种经典实现,包括本地限流和基于Redis的限流。
本地限流(单机版)
适用于单体应用或不需要跨服务共享限流状态的场景,常用算法有令牌桶和滑动窗口。
使用 Guava RateLimiter(令牌桶)
import com.google.common.util.concurrent.RateLimiter;
public class LocalRateLimiter {
// 每秒产生 10 个令牌,即 QPS 上限为 10
private final RateLimiter rateLimiter = RateLimiter.create(10);
public boolean tryAcquire() {
return rateLimiter.tryAcquire();
}
public static void main(String[] args) {
LocalRateLimiter limiter = new LocalRateLimiter();
// 模拟 100 个请求
for (int i = 0; i < 100; i++) {
boolean acquired = limiter.tryAcquire();
if (acquired) {
System.out.println("请求通过");
} else {
System.out.println("请求被限流");
}
}
}
}
基于 AOP + 注解 + Redis(自定义滑动窗口)
// 自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RateLimit {
// 每秒最大请求数
int qps() default 10;
// 限流时间窗口(秒)
int time() default 1;
}
// AOP 切面实现
@Aspect
@Component
public class RateLimitAspect {
@Around("@annotation(rateLimit)")
public Object around(ProceedingJoinPoint joinPoint, RateLimit rateLimit) throws Throwable {
// 模拟本地计数器(实际可用 ConcurrentHashMap + 滑动窗口)
String key = joinPoint.getSignature().toShortString();
// 这里简化为伪代码,实际可使用 Redis + Lua 实现原子计数
if (checkRateLimit(key, rateLimit.qps(), rateLimit.time())) {
return joinPoint.proceed();
} else {
throw new RuntimeException("请求过于频繁,请稍后重试");
}
}
private boolean checkRateLimit(String key, int qps, int time) {
// 真实场景使用 Redis + Lua 脚本保证原子性
// 示例伪逻辑:
// 1. 获取当前时间窗口内的请求次数
// 2. 如果超过上限则返回 false
// 3. 否则计数 +1,返回 true
return true;
}
}
分布式限流(基于 Redis)
适用于微服务架构,多个服务实例共享同一份限流计数器。
Redis + Lua 脚本实现固定窗口
-- Lua 脚本(原子操作)
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local expire = tonumber(ARGV[2])
local current = redis.call('GET', key)
if current and tonumber(current) >= limit then
return 0 -- 限流
end
local count = redis.call('INCR', key)
if count == 1 then
redis.call('EXPIRE', key, expire)
end
return 1 -- 允许通过
Java 调用示例(使用 Spring Data Redis):
@Component
public class RedisRateLimiter {
@Autowired
private StringRedisTemplate redisTemplate;
private static final String LUA_SCRIPT =
"local key = KEYS[1]\n" +
"local limit = tonumber(ARGV[1])\n" +
"local expire = tonumber(ARGV[2])\n" +
"local current = redis.call('GET', key)\n" +
"if current and tonumber(current) >= limit then\n" +
" return 0\n" +
"end\n" +
"local count = redis.call('INCR', key)\n" +
"if count == 1 then\n" +
" redis.call('EXPIRE', key, expire)\n" +
"end\n" +
"return 1";
public boolean tryAcquire(String key, int limit, int expireSeconds) {
DefaultRedisScript<Long> script = new DefaultRedisScript<>(LUA_SCRIPT, Long.class);
Long result = redisTemplate.execute(script, Collections.singletonList(key),
String.valueOf(limit), String.valueOf(expireSeconds));
return result != null && result == 1;
}
}
Redis 令牌桶(进阶)
使用 Redis 的有序集合(ZSet)实现滑动窗口,或使用 Redis 4.0 的令牌桶模块 redis-cell(需要安装)。
# 直接使用 redis-cell 提供的 CL.THROTTLE 命令 CL.THROTTLE user123 10 10 60 1 # 参数解释:key, 最大burst, 每秒令牌数, 时间窗口, 每个请求消耗令牌数
Java 调用:
// 使用 Jedis 调用 CL.THROTTLE
List<String> result = jedis.clThrottle("user123", 10, 10, 60, 1);
// 结果解析:是否允许、剩余令牌、等待时间等
框架级限流方案
Spring Cloud Gateway / Zuul
只需配置文件即可实现路由级别限流:
# Spring Cloud Gateway + Redis 限流示例
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/user/**
filters:
- name: RequestRateLimiter
args:
# 使用 Redis 存储限流状态
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
key-resolver: "#{@userKeyResolver}"
Sentinel(阿里开源)
依赖引入后,只需添加注解即可:
@SentinelResource(value = "getUser", blockHandler = "handleBlock")
public User getUser(String id) {
// 业务逻辑
}
// 限流降级方法
public User handleBlock(String id, BlockException e) {
return new User(); // 返回降级结果
}
限流算法的选择
| 算法 | 特点 | 适用场景 |
|---|---|---|
| 固定窗口 | 实现简单,但临界突变问题 | 对精度要求不高的场景 |
| 滑动窗口 | 精度高,但资源消耗稍大 | 需要平滑限流的 API |
| 令牌桶 | 允许突发流量,平滑速率 | 流量不均匀的接口 |
| 漏桶 | 强制平滑,不允许突发 | 严格控制输入速率(如数据库写入) |
最佳实践总结
- 单机测试 / 非关键接口 → 用 Guava RateLimiter 足够。
- 生产环境微服务 → 优先使用 Sentinel 或 Gateway 限流过滤器,免去复杂配置。
- 高并发自定义场景 → Redis + Lua 脚本实现滑动窗口 / 令牌桶。
- 重要提示:限流策略应包含 降级返回(如 HTTP 429 状态码 + 友好提示),不要直接让服务崩溃。
- 配合熔断:限流只是流量控制的第一步,建议结合 Hystrix / Resilience4j 实现熔断降级。
根据你的业务场景选择合适方案,希望对你有所帮助!
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播