1、计数器限流算法
代码实现:
/**
* 计数器限流算法
*/
public class CounterLimiter {
/**
* 当前时间
*/
private long timeStamp = System.currentTimeMillis();
/**
* 请求数
*/
private int reqCount = 0;
/**
* 每秒限流的最大请求数
*/
private int limitNum = 100;
/**
* 限流时长,3s
*/
private long interval = 3000L;
public synchronized Boolean limit ()
{
// 也可以使用redis计算,利用redis的自动增加的原子性,redisClient.incr(System.currentTimeMillis() / 1000)
// 获取当前时间
long now = System.currentTimeMillis();
// 处于限流时间内
if (now < timeStamp + interval){
// 判断当前请求书是否大于最大请求数
if (reqCount + 1 > limitNum){
return true;
}
reqCount++;
return false;
}
// 不处于限流时间内,开启新增限流时间
timeStamp = now;
reqCount = 0;
return false;
}
}
2、滑动时间窗口算法
代码实现:
/**
* 滑动时间窗口算法
*/
public class SlidingTimeWindowLimiter {
/**
* 总的请求数
*/
private int reqCount = 0;
/**
* 每个窗口的请求数
*/
private LinkedList<Integer> slots = new LinkedList<>();
/**
* 每秒限流的最大请求数
*/
private int limitNum = 100;
/**
* 滑动窗口里的每个格子的时间长度,设置1ms
*/
private long windowLength = 100L;
/**
* 滑动窗口里的格式数量,1s内有10个格子
*/
private int windowNum = 10;
/**
* 初始化
*/
public SlidingTimeWindowLimiter(){
// 初始化一个滑动窗口
slots.add(0);
// 开启线程每隔1ms添加一个滑动窗口
new Thread(() ->{
while (true){
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 添加滑动窗口
slots.add(0);
// 如果当前滑动窗口已经超过10个
if(slots.size() > windowNum){
// 去掉第一个窗口中的请求数
reqCount = reqCount - slots.peekFirst();
// 去掉第一个窗口
slots.removeFirst();
}
}
}).start();
}
/**
* 限流
* @return
*/
public synchronized Boolean limit(){
// 限流
if (reqCount + 1 > limitNum){
return true;
}
// 没有限流
// 设置当前滑动窗口的请求数
slots.set(slots.size() - 1, slots.peekLast() + 1);
// 请求数+1
reqCount++;
return false;
}
}
3、漏桶算法
代码实例:
/**
* 漏桶算法
*/
public class LeakyBucketLimiter {
/**
* 当前时间
*/
private long timeStamp = System.currentTimeMillis();
/**
* 桶的容量(最大能处理的请求数)
*/
private long capacity = 100;
/**
* 桶漏水的速率(每秒能处理的请求数)
*/
private long rate = 10;
/**
* 当前水量(当前累计的请求数)
*/
private long water = 20;
public synchronized Boolean limit (){
long now = System.currentTimeMillis();
// 先执行漏水,计算剩余水量(计算剩余请求次数)
water = Math.max(0, water - ((now - timeStamp) / 1000) * rate);
timeStamp = now;
// 判断桶容量是否已超
// 已超桶容量
if (water + 1 > capacity){
return true;
}
// 没超桶容量
water++;
return false;
}
}
4、令牌桶算法
代码实例:
/**
* 令牌桶限流算法
*/
public class TokenBucketLimiter {
/**
* 当前时间
*/
private long timeStamp = System.currentTimeMillis();
/**
* 桶的容量(最大能处理的请求数)
*/
private long capacity = 100;
/**
* 令牌放入速率(每秒向桶里放入的令牌数量)
*/
private long rate = 10;
/**
* 当前令牌数
*/
private long tokens = 20;
public synchronized Boolean limit(){
// 当前时间
long now = System.currentTimeMillis();
// 计算当前桶里剩余的令牌数
tokens = Math.min(capacity, tokens + (now - timeStamp) * rate);
timeStamp = now;
// 桶里没有令牌则限流
if (tokens < 1){
return true;
}
// 还有令牌则领取令牌
tokens--;
return false;
}
}