Java 限流接口是一种用于控制系统中流量的工具,它可以限制系统在一个设定的时间窗口内处理的请求数量,以保护系统免受过度的请求压力。
为什么要限流?
在一个高并发的系统中,当大量请求同时到达系统时,如果系统无法合理地处理这些请求,可能会导致系统资源被耗尽,甚至崩溃。限流的目的就是为了控制并发请求的数量,防止系统因为过度的请求压力而崩溃。
限流可以带来以下好处:
保护系统资源:限流可以保护有限的系统资源不被过度占用,确保系统能够正常提供服务。
提供公平性:限流可以让系统能够公平地处理请求,防止某些请求占用过多的资源导致其他请求被拒绝或延迟。
防止恶意攻击:通过限制每个用户的请求频率,可以有效防止恶意攻击或恶意刷接口。
如何实现?
常见的 Java 限流实现方式有以下几种:
计数器算法:基于固定窗口的请求计数,当请求数量超过阈值时进行限流。可以使用 AtomicLong 来实现计数器,结合定时任务每秒重置窗口内的计数器。
漏桶算法:漏桶算法通过一个固定容量的漏桶来控制请求的流量。每个请求按照固定的速率往桶中滴水,请求无法被处理时会丢弃。可以使用队列和定时任务来实现漏桶算法。
令牌桶算法:令牌桶算法与漏桶算法类似,但是桶中的令牌容量是固定的。每个请求需要从令牌桶中获取一个令牌才能被处理,当令牌桶为空时,请求被拒绝。可以使用队列和定时任务来实现令牌桶算法。
实现原理:
1.计数器算法
public class RateLimiter {
private AtomicLong counter = new AtomicLong(0);
private int limit;
private int interval;
public RateLimiter(int limit, int interval) {
this.limit = limit;
this.interval = interval;
// 定时任务,每秒重置计数器
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(this::resetCounter, 0, interval, TimeUnit.SECONDS);
}
public boolean allowRequest() {
long currentCount = counter.incrementAndGet();
if (currentCount > limit) {
return false;
}
return true;
}
private void resetCounter() {
counter.set(0);
}}
在上述代码中,我们使用了 AtomicLong 来实现计数器,通过调用allowRequest()方法来判断当前请求是否允许被处理。每秒钟定时任务会重置计数器,这样就限制了每秒钟处理的请求数量。
计数器算法实现简单粗暴,单机在Java中可用Atomic等原子类或Semaphore,分布式就用Redis incr。这个算法虽然简单,但是有一个十分致命的问题,那就是临界问题。
假设有一个恶意用户,他在0:59时,瞬间发送了100个请求,并且1:00又瞬间发送了100个请求,那么其实这个用户在 1秒里面,瞬间发送了200个请求。
我们刚才规定的是1分钟最多100个请求(规划的吞吐量),也就是每秒钟最多1.7个请求,用户通过在时间窗口的重置节点处突发请求, 可以瞬间超过我们的速率限制。用户有可能通过算法的这个漏洞,瞬间压垮我们的应用。
2.漏桶算法
漏桶算法是另一种经典的限流算法之一,它的实现原理是通过一个固定容量的漏桶来控制请求的流量。漏桶的容量就像一根固定大小的水管,请求被视为流入水管的水,水根据一定速率(容量大小)流出水管。如果水管满了,水就会溢出,这些超出限制的请求将会被丢弃或拒绝处理。
漏桶的主要实现思路是在固定的时间内,让一个漏桶按照确认容量流出,若请求流入漏桶时漏桶已满,则拒绝这个请求。
public class LeakyBucketLimiter {
private final int maxBucketSize;//滴漏速率,即每秒钟最多能处理的请求个数
private final double leakRate;//桶内漏水速度,漏水速度会影响桶内剩余的水量
private volatile int currentBucketSize;//当前桶中的水量
private volatile long lastLeakTime;//上一次漏水的时间
public LeakyBucketLimiter(int maxBucketSize, double leakRate) {
this.maxBucketSize = maxBucketSize;
this.leakRate = leakRate;
this.currentBucketSize = 0;
this.lastLeakTime = System.currentTimeMillis();
}
/**
* 尝试获取请求处理的权限,返回true表示允许,返回false表示拒绝
*/
public synchronized boolean tryAcquire(int requestCount) {
long now = System.currentTimeMillis();
double leakedWater = ((now - lastLeakTime) / 1000.0) * leakRate;
if (currentBucketSize + leakedWater > maxBucketSize) {
//桶已满,拒绝处理请求
return false;
}
currentBucketSize += leakedWater;
currentBucketSize = Math.min(currentBucketSize + requestCount, maxBucketSize);
lastLeakTime = now;
return true;
}}
漏桶算法的优点是可以平滑处理请求流量,并且可以设置一个固定的处理速度,即漏桶的容量大小,保证每秒钟最多能处理的请求个数。缺点是在短时间内会拒绝大量的请求,因此可能会影响一些特定的业务场景的实现。
3.令牌桶算法
令牌桶算法是另一种常见的限流算法,类似于漏桶算法,但它与漏桶算法实现上有所不同。令牌桶算法将固定容量的桶划分为宽度固定的小块(令牌),请求需要使用令牌才能被处理。每秒钟会往桶中投放若干个令牌,每个令牌就代表一个请求,如果桶中的令牌被取完了,那么后面的请求就会直接被拒绝或被阻塞,直到有足够的令牌才能被处理。
public class TokenBucketLimiter {
private int maxTokenSize;//桶的大小,表示最多存储的令牌个数
private double rate;//令牌的投放速度,表示每毫秒允许添加的令牌数
private volatile int currentTokenCount;//当前令牌数
private volatile long lastTokenTime;//上次填充令牌时间
public TokenBucketLimiter(int maxTokenSize, double rate) {
this.maxTokenSize = maxTokenSize;
this.rate = rate;
this.currentTokenCount = maxTokenSize;
this.lastTokenTime = System.currentTimeMillis();
}
/**
* 尝试获取请求处理的权限,返回true表示允许,返回false表示拒绝
*/
public synchronized boolean tryAcquire() {
long now = System.currentTimeMillis();
double newTokens = (now - lastTokenTime) * rate;
if (newTokens > 0) {
currentTokenCount = Math.min(currentTokenCount + (int) newTokens, maxTokenSize);
lastTokenTime = now;
}
if (currentTokenCount > 0) {
currentTokenCount--;
return true;
}
return false;
}}
令牌桶算法的优点是可以在一定程度上适应突发流量的处理,能够快速响应。而且它允许在延迟较大的情况下,一定程度上支持突发流量处理。令牌桶算法还能够平滑地处理请求,限制了请求的处理速度,提供了更好的流量控制。缺点是对短时间突发流量的处理相对较差,可能会出现短期内无法处理大量请求的情况。漏桶算法和令牌桶算法都是有效的限流算法,适用于不同的业务场景。
计数器算法简单易用,但是有临界问题。漏桶算法可以平滑处理请求流量,但可能会在短时间内拒绝大量的请求。令牌桶算法可以在一定程度上适应突发流量的处理,但可能在短时间内无法处理大量请求。根据具体业务需求和场景特点,选择合适的算法来实现限流策略。
限流是一种重要的技术手段,可以保护系统免受过度的请求压力。在实际的应用开发中,根据具体的业务场景和需求选择适合的限流算法来实现,并根据系统的实际情况设置合理的限流参数。通过合理的限流策略,可以确保系统的稳定性和可靠性。
>>>更多开发技术资源、资讯请关注访问【昂焱数据】
领取专属 10元无门槛券
私享最新 技术干货