Java实现接口限流,通常有三种方案,分别是计数器算法、令牌桶算法和漏桶算法。下面分别介绍这三种方案的实现方法和代码示例。
1. 计数器算法
计数器算法的核心思想是,对窗口内的API请求进行计数,当计数超过设定的阈值时,拒绝请求。其中,窗口有两种实现方式:滑动窗口和计时窗口。
滑动窗口的实现方法如下(以限制1秒内请求不超过5次为例):
1.1 代码实现
import java.util.concurrent.ArrayBlockingQueue;
public class SlidingWindowRateLimiter {
private int permitsPerSecond;
private int maxPermits;
private volatile int count;
private ArrayBlockingQueue<Long> timestamps;
public SlidingWindowRateLimiter(int permitsPerSecond, int maxPermits) {
this.permitsPerSecond = permitsPerSecond;
this.maxPermits = maxPermits;
this.count = 0;
this.timestamps = new ArrayBlockingQueue<>(maxPermits);
for (int i = 0; i < maxPermits; i++) {
this.timestamps.offer(System.currentTimeMillis() / 1000);
}
}
public synchronized boolean tryAcquire() {
long now = System.currentTimeMillis() / 1000;
long last = this.timestamps.poll();
this.timestamps.offer(now);
this.count += this.permitsPerSecond * (now - last);
if (this.count > this.maxPermits) {
this.count = this.maxPermits;
}
if (this.count <= 0) {
return false;
} else {
this.count--;
return true;
}
}
}
1.2 示例说明
public class TestSlidingWindowRateLimiter {
public static void main(String[] args) throws InterruptedException {
int permitsPerSecond = 5;
int maxPermits = 10;
SlidingWindowRateLimiter rateLimiter = new SlidingWindowRateLimiter(permitsPerSecond, maxPermits);
while (true) {
if (rateLimiter.tryAcquire()) {
System.out.println("请求成功");
} else {
System.out.println("请求失败");
}
Thread.sleep(200);
}
}
}
运行上述示例,可以看到程序每隔200毫秒尝试向接口发送请求,当请求次数超过10次时,接口将返回“请求失败”的提示信息。
2. 令牌桶算法
令牌桶算法的核心思想是,维护一个令牌桶,每秒钟往桶中添加一定数量的令牌,API请求从桶中获取令牌,如果桶中没有令牌,则拒绝请求。
2.1 代码实现
import java.util.concurrent.*;
public class TokenBucketRateLimiter {
private int permitsPerSecond;
private int maxPermits;
private volatile int count;
private final ScheduledExecutorService scheduler;
private ScheduledFuture<?> scheduledFuture;
public TokenBucketRateLimiter(int permitsPerSecond, int maxPermits) {
this.permitsPerSecond = permitsPerSecond;
this.maxPermits = maxPermits;
this.count = maxPermits;
this.scheduler = Executors.newScheduledThreadPool(1);
this.scheduledFuture = this.scheduler.scheduleAtFixedRate(() -> {
int newCount = count + permitsPerSecond;
if (newCount > maxPermits) {
count = maxPermits;
} else {
count = newCount;
}
}, 0, 1, TimeUnit.SECONDS);
}
public synchronized boolean tryAcquire() {
if (this.count <= 0) {
return false;
} else {
this.count--;
return true;
}
}
public void shutdown() {
this.scheduledFuture.cancel(true);
this.scheduler.shutdownNow();
}
}
2.2 示例说明
public class TestTokenBucketRateLimiter {
public static void main(String[] args) throws InterruptedException {
int permitsPerSecond = 1;
int maxPermits = 10;
TokenBucketRateLimiter rateLimiter = new TokenBucketRateLimiter(permitsPerSecond, maxPermits);
while (true) {
if (rateLimiter.tryAcquire()) {
System.out.println("请求成功");
} else {
System.out.println("请求失败");
}
Thread.sleep(500);
}
}
}
运行上述示例,可以看到程序每隔0.5秒尝试向接口发送请求,当桶中没有令牌时,接口将返回“请求失败”的提示信息。
3. 漏桶算法
漏桶算法的核心思想是,限制请求发送速率,即将API请求压入一个漏桶中,漏桶以固定速率将请求处理,当API请求超过漏桶最大容量时,拒绝请求。
3.1 代码实现
import java.util.concurrent.TimeUnit;
public class LeakyBucketRateLimiter {
private int permitsPerSecond;
private int maxPermits;
private volatile int count;
private long lastLeakTime;
public LeakyBucketRateLimiter(int permitsPerSecond, int maxPermits) {
this.permitsPerSecond = permitsPerSecond;
this.maxPermits = maxPermits;
this.count = 0;
this.lastLeakTime = System.currentTimeMillis();
}
public boolean tryAcquire() {
long now = System.currentTimeMillis();
long leakTime = (now - lastLeakTime) / 1000;
lastLeakTime = now;
int leakCount = (int) (leakTime * permitsPerSecond);
count = Math.max(0, count - leakCount);
if (count >= maxPermits) {
return false;
} else {
count++;
return true;
}
}
}
3.2 示例说明
public class TestLeakyBucketRateLimiter {
public static void main(String[] args) throws InterruptedException {
int permitsPerSecond = 1;
int maxPermits = 10;
LeakyBucketRateLimiter rateLimiter = new LeakyBucketRateLimiter(permitsPerSecond, maxPermits);
while (true) {
if (rateLimiter.tryAcquire()) {
System.out.println("请求成功");
} else {
System.out.println("请求失败");
}
Thread.sleep(500);
}
}
}
运行上述示例,可以看到程序每隔0.5秒尝试向接口发送请求,当请求数量超过漏桶的最大容量时,接口将返回“请求失败”的提示信息。
以上三种接口限流算法均有各自的优缺点,可根据具体需求选择适合的实现方式。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java实现接口限流方案 - Python技术站