摘要 在高并发应用中,限流是保证系统稳定的重要措施之一。滑动窗口(Sliding Window)限流算法因其灵活性和准确性而备受青睐。本文详细介绍滑动窗口的设计思路,并提供了适合初学者的代码示例,帮助大家快速掌握该限流策略。
随着互联网业务的快速发展,流量控制在高并发场景下显得尤为重要。限流策略有很多种,滑动窗口是一种能平滑处理请求流量的限流方式,相较于固定窗口更精准,适合负载波动大的场景。本文旨在帮助初学者从原理、实现到代码示例全面掌握滑动窗口限流。
滑动窗口限流是一种通过细粒度时间划分,实现更平滑的限流效果的算法。它可以有效避免固定窗口在时间边界处流量突增的问题。在滑动窗口中,将一个完整窗口分为多个小区间,计数器会不断刷新,使得统计的请求数更精准。
假设限流窗口为1秒钟,分为10个100毫秒的小区间,每秒允许的最大请求数为100。当窗口内请求达到100时,当前窗口的后续请求将被拒绝,待窗口滑动后重新计数。
以下是基于Java的滑动窗口限流代码示例。通过使用循环队列的方式实现滑动窗口,逐个区间计数,并在窗口滑动时进行统计。
import java.util.LinkedList;
import java.util.Queue;
public class SlidingWindowRateLimiter {
private final int limit; // 每窗口最大请求数
private final long windowSizeInMillis; // 窗口大小(毫秒)
private final int slotCount; // 窗口划分的区间数
private final long slotSizeInMillis; // 每个区间大小(毫秒)
private Queue<Integer> slots; // 滑动窗口的请求数队列
private long lastRefreshTime; // 上次刷新时间
public SlidingWindowRateLimiter(int limit, long windowSizeInMillis, int slotCount) {
this.limit = limit;
this.windowSizeInMillis = windowSizeInMillis;
this.slotCount = slotCount;
this.slotSizeInMillis = windowSizeInMillis / slotCount;
this.slots = new LinkedList<>();
for (int i = 0; i < slotCount; i++) {
slots.add(0);
}
this.lastRefreshTime = System.currentTimeMillis();
}
public synchronized boolean allowRequest() {
refreshSlots(); // 更新窗口内的区间计数
// 累计当前窗口内的请求总数
int currentWindowRequestCount = slots.stream().mapToInt(Integer::intValue).sum();
if (currentWindowRequestCount < limit) {
// 若未超限,则放行并记录请求
int lastSlot = slots.poll();
slots.add(lastSlot + 1); // 增加当前区间的请求计数
return true;
} else {
// 请求超过阈值,拒绝请求
return false;
}
}
// 更新窗口区间的请求计数
private void refreshSlots() {
long currentTime = System.currentTimeMillis();
long elapsedTime = currentTime - lastRefreshTime;
if (elapsedTime >= slotSizeInMillis) {
int slotsToUpdate = (int) (elapsedTime / slotSizeInMillis);
for (int i = 0; i < Math.min(slotsToUpdate, slotCount); i++) {
slots.poll();
slots.add(0); // 初始化新时间片的请求计数
}
lastRefreshTime = currentTime - (elapsedTime % slotSizeInMillis);
}
}
public static void main(String[] args) throws InterruptedException {
SlidingWindowRateLimiter limiter = new SlidingWindowRateLimiter(5, 1000, 10);
// 测试连续请求
for (int i = 0; i < 15; i++) {
System.out.println("请求 " + (i + 1) + ": " + (limiter.allowRequest() ? "通过" : "拒绝"));
Thread.sleep(100);
}
}
}
优点
缺点
滑动窗口限流是一种灵活而精准的流量控制算法,适合高并发的业务场景。在实际使用中,可以根据业务特点灵活调整窗口大小和分区数量,以平衡流量控制精度与系统开销。希望本文能帮助大家更好地理解和实现滑动窗口限流。