概念:
滑动窗口去重的目标是在一定时间范围内,避免处理重复请求,常用于去除重复的 API 调用、订单请求、发送消息等。
实现原理:
- 请求哈希存储: 通过唯一标识(如用户 ID、请求参数、消息 ID)生成哈希值,存入缓存(如 Redis、Guava Cache)。
- 时间窗口: 设置一个固定的时间窗口(如 5 秒),在窗口期内如果相同请求再次到来,则认为是重复请求。
- 滑动检查: 随着窗口的滑动,每次检查当前时间范围内是否存在相同的请求,若存在则丢弃。
简单实现:
public class SlidingWindowLimiter {
private final int maxRequests;
private final long windowSizeMillis;
private final LinkedList<Long> requestTimestamps = new LinkedList<>();
public SlidingWindowLimiter(int maxRequests, long windowSizeSeconds) {
this.maxRequests = maxRequests;
this.windowSizeMillis = windowSizeSeconds * 1000;
}
public synchronized boolean allowRequest() {
long currentTime = System.currentTimeMillis();
long windowStart = currentTime - windowSizeMillis;
// 移除不在窗口范围内的请求
while (!requestTimestamps.isEmpty() && requestTimestamps.peek() < windowStart) {
requestTimestamps.poll();
}
//判断窗口范围内的请求是否超过规定范围,如果没超过就放行,超过就拒绝
if (requestTimestamps.size() < maxRequests) {
requestTimestamps.add(currentTime);
return true;
} else {
return false;
}
}
}