参考教程:2小时吃透4种分布式限流算法
1.计数器限流
public class CounterLimiter {
// 开始时间
private static long startTime = System.currentTimeMillis();
// 时间间隔,单位为ms
private long interval = 1000L;
// 限制访问次数
private int limitCount = 2;
// 访问次数
private int reqCount = 0;
private synchronized boolean tryAcquire(){
long nowTime = System.currentTimeMillis();
if(nowTime < startTime + interval){
if(reqCount + 1 > limitCount){
System.out.println(Thread.currentThread().getName() + "被限流了");
return true;
}
reqCount++;
System.out.println(Thread.currentThread().getName() + "通过了");
return false;
}else {
reqCount = 1;
startTime = nowTime;
System.out.println(Thread.currentThread().getName() + "通过了");
return false;
}
}
public static void main(String[] args) {
CounterLimiter counterLimiter = new CounterLimiter();
for (int i = 0; i < 10; i++) {
new Thread(() ->{
counterLimiter.tryAcquire();
}).start();
}
}
}
2.滑动时间窗口限流
import java.util.LinkedList;
public class SlidingTimeWindowLimiter {
// 请求数量
private int reqCount;
// 窗口集合
private LinkedList<Integer> slots = new LinkedList<>();
// 限制访问量
private int limitNum = 2;
// 窗口数量
private int windowNum = 100;
// 每个窗口的时间范围,单位ms
private long windowLength = 100L;
public synchronized Boolean limit(){
if(reqCount + 1 > limitNum){
System.out.println(Thread.currentThread().getName() + ": 被拦截了");
return true;
}
reqCount++;
slots.set(slots.size() - 1, slots.peekLast() + 1);
System.out.println(Thread.currentThread().getName() + ": 通过了");
return false;
}
public SlidingTimeWindowLimiter(){
slots.addLast(0);
new Thread(() -> {
while (true){
try {
Thread.sleep(windowLength);
}catch (InterruptedException e){
e.printStackTrace();
}
slots.addLast(0);
if(slots.size() > windowNum){
reqCount = reqCount - slots.peekLast();
slots.removeLast();
System.out.println("滑动格子:" + reqCount);
}
}
}).start();
}
public static void main(String[] args) {
SlidingTimeWindowLimiter slidingTimeWindowLimiter = new SlidingTimeWindowLimiter();
for (int i = 0; i < 10; i++) {
new Thread(() -> {
slidingTimeWindowLimiter.limit();
}).start();
}
}
}
3.漏桶算法
public class LeakyBucketLimiter {
// 初始时间
private long timestamp = System.currentTimeMillis();
// 漏桶容量
private long capacity = 5;
// 流出速率
private long rate = 10;
// 桶内有多少请求
private long water = 0;
public synchronized Boolean limit(){
long now = System.currentTimeMillis();
water = Math.max(0, water - (now - timestamp) / 1000 * rate);
timestamp = now;
if((water + 1) <= capacity){
water++;
System.out.println(Thread.currentThread().getName() + "通过了");
return false;
}else{
System.out.println(Thread.currentThread().getName() + "被拦截了");
return true;
}
}
public static void main(String[] args) {
LeakyBucketLimiter counterLimiter = new LeakyBucketLimiter();
for (int i = 0; i < 10; i++) {
new Thread(() ->{
counterLimiter.limit();
}).start();
}
}
}
4.令牌桶算法
public class TokenBucketLimiter {
// 初始时间
private long timeStamp = System.currentTimeMillis();
// 令牌桶容量
private long capacity = 5;
// 每秒生成令牌的数量
private long rate = 2;
// 桶内的令牌数
private long tokens = 0;
public synchronized Boolean limit(){
long now = System.currentTimeMillis();
tokens = Math.min(capacity, tokens + (now - timeStamp) * rate);
timeStamp = now;
// 没有令牌了
if(tokens < 1){
System.out.println(Thread.currentThread().getName() + "被拦截了");
return true;
}else {
tokens--;
System.out.println(Thread.currentThread().getName() + "通过了");
return false;
}
}
public static void main(String[] args) {
TokenBucketLimiter slidingTimeWindowLimiter = new TokenBucketLimiter();
for (int i = 0; i < 10; i++) {
new Thread(() -> {
slidingTimeWindowLimiter.limit();
}).start();
}
}
}