1、实现逻辑
记录用户每次的访问时间,因此对于每个用户,用列表类型的键记录他最近100次访问的时间。
如果键中的元素超过100个,就判断时间最早的元素距离现在的时间是否小于1分钟,如果是,则表示用户最近1分钟的访问次数超过100次,如果不是就将当前时间加入列表中,同时把最早的元素删除
2、LUA脚本
使用lua脚本实现,保证多个操作的“原子性”
参数说明:
- KEYS[1] 传入表示用户唯一标识的键
- ARGV[1] 传入限制的访问次数
lua脚本如下:
local len = redis.call('llen',KEYS[1]);
redis.replicate_commands(); -- 防止随机写入
local now = redis.call('TIME')[1]; -- 当前系统时间,单位是秒
if len < tonumber(ARGV[1]) then
redis.call('lpush',KEYS[1],now);
return 0;
else
local lasttime = redis.call('lindex',KEYS[1],-1); -- 取最后一个元素
if now - lasttime < 60 then -- 访问频率超过限制 ,这里的60是指60秒
return -1;
else -- 访问频率未超出限制
redis.call('lpush',KEYS[1],now);
redis.call('ltrim',KEYS[1],0,tonumber(ARGV[1])-1); -- 删除索引在[0,访问次数-1]以外的元素
return 0;
end;
end;
3、代码实现(java)
/**
* 执行lua脚本
*
* @param luaScript lua脚本
* @param keyParams lua脚本中KEYS参数 key
* @param argvParams lua脚本中ARGV参数 10
*/
Long result = redisTemplate.execute(
RedisScript.of(luaScript, Long.class),
Collections.singletonList(keyParams),
argvParams);
//返回0表示未超过限制的条数 可继续发送
if(result == 0) {
return true;
}