基于Redis ZSet的滑动窗口限流
2024-10-29 17:25:11 2
private boolean limit() {
String ip = ServletUtil.getClientIP(request);
String banKey = "limit_ban_" + ip;
Boolean b = redisTemplate.hasKey(banKey);
if (Objects.nonNull(b) && b) {
return false;
}
String key = "service_limit_" + ip;
long currMs = System.currentTimeMillis();
ZSetOperations<String, String> ops = redisTemplate.opsForZSet();
// 根据score查最近半小时的新增元素
Set<String> set = ops.rangeByScore(key, currMs - 1000 * 60 * 30.0, currMs);
// 半小时内请求超过30次
if (Objects.nonNull(set) && set.size() >= 30) {
// 超过请求次数限制, 封禁30分钟
redisTemplate.opsForValue().set(banKey, "1", 30, TimeUnit.MINUTES);
return false;
}
// 将当前毫秒当成score存入zset
// 请求一次存一次
ops.add(key, Long.toString(currMs), currMs);
redisTemplate.expire(key, 30, TimeUnit.MINUTES);
return true
}