基于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);
}
}
}

}

posted on 2020-07-01 18:01  街机玩家  阅读(368)  评论(0编辑  收藏  举报

导航