Springboot + zset + lua 实现滑动窗口
@Component
public class RedisRateLimiter {
@Autowired
private RedisTemplate<String, String> redisTemplate;
private String luaScript() {
return "redis.call('zremrangebyscore', KEYS[1], 0, tonumber(ARGV[1]) - tonumber(ARGV[2]) * 1000) " + // 移除过期的元素
"if tonumber(redis.call('zcard',KEYS[1])) < tonumber(ARGV[3]) then " + // 获取当前窗口内的元素数量,如果当前窗口内的元素数据超过窗口大小,删除最旧的元素, 窗口内的元素数量小于窗口大小
"redis.call('zadd', KEYS[1], tonumber(ARGV[1]), tonumber(ARGV[1])) " + // 将新元素添加到ZSET中
"redis.call('expire', KEYS[1], tonumber(ARGV[2])) " + // 设置过期时间
"return true " +
"else " +
"return false " +
"end";
}
public boolean slideWindowAlgorithmByLua(String key, int limitCount, long windowTime) {
long currentTime = System.currentTimeMillis();
List<String> argList = new ArrayList<>();
argList.add(String.valueOf(currentTime));
argList.add(String.valueOf(windowTime));
argList.add(String.valueOf(limitCount));
RedisScript<Boolean> redisScript = new DefaultRedisScript<>(this.luaScript(), Boolean.class);
return Boolean.TRUE.equals(redisTemplate.execute(redisScript, Collections.singletonList(key), argList.toArray()));
}
}
亲测有效,有何问题,请批评指正!