import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 漏桶算法工具类
*/
public class BucketLimitUtil {
public static final Map<String, Funnel> funnelMap = new ConcurrentHashMap<>();
/**
* 根据给定的漏斗参数检查是否允许访问
*
* @param capacity 漏斗容量
* @param allowQuota 每单个单位时间允许的流量
* @param perSecond 单位时间(秒)
* @param key funnelMap中key值
* @return 是否允许访问
*/
public static boolean isActionAllowed(int capacity, int allowQuota, int perSecond, String key) {
// String key = "funnelKey";
if (!funnelMap.containsKey(key)) {
funnelMap.put(key, new Funnel(capacity, allowQuota, perSecond));
}
Funnel funnel = funnelMap.get(key);
return funnel.watering(1);
}
private static class Funnel {
//容量
private final int capacity;
//泄露率
private final float leakingRate;
//剩余流量
private int leftQuota;
//
private long leakingTs;
private int restoreQuota;
/**
* @param capacity 漏斗容量
* @param count 每单个单位时间允许的流量
* @param perSecond 单位时间(秒)
*/
public Funnel(int capacity, int count, int perSecond) {
this.capacity = capacity;
// 因为计算使用毫秒为单位的
perSecond *= 1000;
this.leakingRate = (float) count / perSecond;
}
/**
* 根据上次水流动的时间,腾出已流出的空间
*/
private void makeSpace() {
long now = System.currentTimeMillis();
long time = now - leakingTs;
int leaked = (int) (time * leakingRate);
if (leaked < 1) {
return;//表示超出速率
}
leftQuota += leaked;
restoreQuota += leaked;
// 如果剩余大于容量,则剩余等于容量
if (leftQuota > capacity) {
leftQuota = capacity;
}
if (restoreQuota > capacity) {
restoreQuota = 0;
leftQuota = capacity;
}
leakingTs = now;
}
/**
* 漏斗漏水
*
* @param quota 流量
* @return 是否有足够的水可以流出(是否允许访问)
*/
public boolean watering(int quota) {
makeSpace();
int left = leftQuota - quota;
if (left >= 0) {
leftQuota = left;
return true;
}
return false;
}
}
public static void clear(String key) {
Funnel funnel = funnelMap.remove(key);
}
}
【漏斗桶】
最新推荐文章于 2024-09-06 10:38:06 发布