准备
public interface LimiterConstants {
//计数器
//限制请求次数3次
int COUNTER_LIMIT_NUM = 3;
//间隔时间1s
long COUNTER_INTERVAL = 100000L;
//滑动窗口
//滑动窗口每个格子时间大小 100ms
long SLIDING_WINDOW_LENGTH = 100L;
//滑动窗口个数 10个 即100*10 = 1000ms = 1s
int SLIDING_WINDOW_NUM = 10;
//漏桶
//漏桶容量
long LEAK_BUCKET_CAPACITY = 100L;
//漏桶漏水速率
long LEAK_BUCKET_RATE = 10L;
//令牌桶
//令牌桶容量
long TOKEN_CAPACITY = 100L;
//令牌桶放入速率
long TOKEN_RATE = 10L;
}
public interface TrafficLimiter {
public Boolean limiter();
}
计数器
@Service
public class CounterLimiterImpl implements TrafficLimiter {
private long timestamp = System.currentTimeMillis();
//已经请求次数
private int reqCnt = 0;
@Autowired
private RedisTemplate redisTemplate;
@Override
public synchronized Boolean limiter() {
long now = System.currentTimeMillis();
if (now < timestamp + COUNTER_INTERVAL) {
reqCnt++;
//计数器超过限制次数,返回true
return reqCnt > COUNTER_LIMIT_NUM;
} else {
//更新时间窗口
timestamp = now;
//重置计数器
reqCnt = 1;
}
return false;
/*
Long count = redisTemplate.opsForValue().increment("counter", 1);
if (1 == count) {
redisTemplate.expire("counter", COUNTER_INTERVAL, TimeUnit.MILLISECONDS);
}
if (count > COUNTER_LIMIT_NUM) {
return true;
}
return false;
*/
}
}
滑动时间窗口
@Service
public class SlidingTimeWindowLimiterImpl implements TrafficLimiter {
//已经请求次数
private int reqCnt = 0;
//每个窗口的请求个数
private final LinkedList<Integer> list = new LinkedList<>();
@Override
public synchronized Boolean limiter() {
reqCnt++;
if (reqCnt > COUNTER_LIMIT_NUM) {
return true;
}
list.set(list.size() - 1, list.peekLast() + 1);
return false;
}
//无参方法初始化
public SlidingTimeWindowLimiterImpl() {
//初始化第一个窗口
list.add(0);
new Thread(() -> {
while (true) {
//每隔SLIDING_WINDOW_LENGTH毫秒创建新窗口
try {
Thread.sleep(SLIDING_WINDOW_LENGTH);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (this) {
list.add(0);
//移除最前面的窗口
if (list.size() > SLIDING_WINDOW_NUM) {
reqCnt -= list.get(0);
list.removeFirst();
}
}
}
}).start();
}
}
漏桶
@Service
public class LeakBuckLimiterImpl implements TrafficLimiter {
private long timestamp = System.currentTimeMillis();
//当前累计任务量
private long water = 0;
@Override
public synchronized Boolean limiter() {
long now = System.currentTimeMillis();
//获取现在的水(减去漏掉的水,保证不为负数)
water = Math.max(0, water - (now - timestamp) / 1000 * LEAK_BUCKET_RATE);
//更新时间
timestamp = now;
water++;
return water > LEAK_BUCKET_CAPACITY;
}
}
令牌桶
就是漏桶反过来
@Service
public class TokenBucketLimiterImpl implements TrafficLimiter {
private long timestamp = System.currentTimeMillis();
//当前令牌桶数量
private long token = 0;
@Override
public synchronized Boolean limiter() {
long now = System.currentTimeMillis();
token = Math.min(TOKEN_CAPACITY, token + (now - timestamp) / 1000 * TOKEN_RATE);
timestamp = now;
token--;
return token < 0;
}
}