在 java 生态中,除了 guava 的 ratelimiter,还有多种限流方案可供选择。以下是几种常见的替代方案:
1. spring cloud gateway / spring cloud alibaba sentinel
适用于: spring cloud 微服务架构
// 在spring cloud gateway中的配置
@bean
public routelocator customroutelocator(routelocatorbuilder builder) {
return builder.routes()
.route("qrcode_route", r -> r.path("/api/qrcode/**")
.filters(f -> f.requestratelimiter()
.ratelimiter(redisratelimiter.class, config -> {
config.setburstcapacity(20);
config.setreplenishrate(10);
}))
.uri("http://localhost:8080"))
.build();
}
2. resilience4j ratelimiter
适用于: 需要更丰富熔断限流功能的场景
// 添加依赖
implementation 'io.github.resilience4j:resilience4j-ratelimiter:1.7.1'
// 使用示例
ratelimiterconfig config = ratelimiterconfig.custom()
.limitrefreshperiod(duration.ofseconds(1))
.limitforperiod(10)
.timeoutduration(duration.ofmillis(100))
.build();
ratelimiter ratelimiter = ratelimiter.of("qrcodelimiter", config);
checkedrunnable restrictedcall = ratelimiter
.decoratecheckedrunnable(ratelimiter, () -> generateqrcode());
try.run(restrictedcall)
.onfailure(throwable -> response.senderror(429, "请求过于频繁"));
3. bucket4j
适用于: 需要分布式限流的场景
// 添加依赖
implementation 'com.github.vladimir-bukhtoyarov:bucket4j-core:7.0.0'
// 本地限流示例
bandwidth limit = bandwidth.classic(10, refill.intervally(10, duration.ofseconds(1)));
bucket bucket = bucket.builder().addlimit(limit).build();
if (bucket.tryconsume(1)) {
// 处理请求
} else {
response.senderror(429, "请求过于频繁");
}
4. redis + lua 分布式限流
适用于: 分布式环境下的精确限流
// redis限流脚本
private static final string limit_script =
"local key = keys[1]\n" +
"local limit = tonumber(argv[1])\n" +
"local expire = tonumber(argv[2])\n" +
"local current = tonumber(redis.call('get', key) or 0\n" +
"if current + 1 > limit then\n" +
" return 0\n" +
"else\n" +
" redis.call('incr', key)\n" +
" if current == 0 then\n" +
" redis.call('expire', key, expire)\n" +
" end\n" +
" return 1\n" +
"end";
public boolean tryacquire(string key, int limit, int expiresec) {
long result = redistemplate.execute(
new defaultredisscript<>(limit_script, long.class),
collections.singletonlist(key),
string.valueof(limit), string.valueof(expiresec));
return result != null && result == 1;
}
// 使用
if (!redislimiter.tryacquire("qrcode:"+ip, 10, 60)) {
response.senderror(429, "请求过于频繁");
return;
}
5. spring aop 实现简单限流
适用于: 简单的单体应用限流
@aspect
@component
public class ratelimitaspect {
private final map<string, atomicinteger> counters = new concurrenthashmap<>();
private final map<string, long> timestamps = new concurrenthashmap<>();
@around("@annotation(ratelimit)")
public object limit(proceedingjoinpoint pjp, ratelimit ratelimit) throws throwable {
string key = ratelimit.key();
int limit = ratelimit.limit();
long interval = ratelimit.interval();
long now = system.currenttimemillis();
if (timestamps.getordefault(key, 0l) + interval < now) {
timestamps.put(key, now);
counters.put(key, new atomicinteger(0));
}
if (counters.getordefault(key, new atomicinteger(0)).incrementandget() > limit) {
throw new responsestatusexception(httpstatus.too_many_requests, "请求过于频繁");
}
return pjp.proceed();
}
}
// 自定义注解
@retention(retentionpolicy.runtime)
@target(elementtype.method)
public @interface ratelimit {
string key() default "";
int limit() default 10;
long interval() default 1000; // ms
}
// 在controller方法上使用
@ratelimit(key = "qrcode", limit = 5, interval = 60000)
@getmapping("/generate")
public void generateqrcode(...) { ... }
6. apache commons pool 对象池限流
适用于: 需要控制资源并发使用的场景
genericobjectpool<object> pool = new genericobjectpool<>(new basepooledobjectfactory<>() {
@override
public object create() {
return new object();
}
});
pool.setmaxtotal(10); // 最大并发数
try {
object permit = pool.borrowobject();
try {
generateqrcode(...);
} finally {
pool.returnobject(permit);
}
} catch (exception e) {
response.senderror(429, "系统繁忙,请稍后再试");
}
选择建议
- 单体应用:spring aop 或 resilience4j
- 微服务架构:spring cloud gateway 或 sentinel
- 分布式系统:redis + lua 或 bucket4j
- 需要丰富特性:resilience4j(支持熔断、限流、重试等)
- 简单需求:guava ratelimiter 仍然是不错的选择
所有方案都可以与你的二维码生成接口集成,根据你的架构复杂度和具体需求选择合适的限流方案。
到此这篇关于java实现限流的6种方案详解的文章就介绍到这了,更多相关java限流内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论