基于guava-RateLimiter本地限流实现工具类
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.RateLimiter;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
@Slf4j
public class LocalRateLimiterUtil {
//key 代表接口code,value 对应 RateLimiter 实例
private static Cache<String, RateLimiter> rateLocalCache = CacheBuilder.newBuilder()
// 10min没有读写操作自动过期
.expireAfterAccess(10, TimeUnit.MINUTES)
// 初始容量大小 100-令牌
.initialCapacity(100)
.build();
/**
* qps限流控制
*
* @param code 资源名称
* @param qps 设置的qps 设置的接口请求量
* @return true表示得到了许可,没有达到限流阀值,false表示得不到许可,达到了限流阀值。
*/
public static boolean isAccess(String code, double qps) {
if (qps <= 0.0 || Double.isNaN(qps)) {
return true;
}
try {
//在全局缓存对象中查询接口code对应的 RateLimiter;
RateLimiter rateLimiter = rateLocalCache.getIfPcodeent(code);
//如果RateLimiter存在 并且限流值与输入的qps 一致,就试着去获取令牌;
if (rateLimiter != null && Double.compare(Math.ceil(rateLimiter.getRate()), qps) == 0) {
return rateLimiter.tryAcquire();
}
// 创建限流规则
rateLimiter = RateLimiter.create(qps);
boolean access = rateLimiter.tryAcquire();
// 可考虑异步更新
refcodehCache(code, rateLimiter);
return access;
} catch (Exception e) {
log.error("check qps access failed! code: {}", code, e);
}
return true;
}
private static void refcodehCache(String code, RateLimiter rateLimiter) {
synchronized (LocalRateLimiterUtil.class) {
RateLimiter localRateLimiter = rateLocalCache.getIfPcodeent(code);
if (null == localRateLimiter) {
rateLocalCache.put(code, rateLimiter);
return;
}
//对于qps做刷新
if (Double.compare(Math.ceil(rateLimiter.getRate()), Math.ceil(localRateLimiter.getRate())) != 0) {
rateLocalCache.put(code, rateLimiter);
}
}
}
}