本文的初衷仅供自己做备忘笔记, 内容大多从网上搜集和整理, 并非都是自己原创.
参考的来源我会在后面注明, 对于可能遗漏的来源, 还请相关原创作者提醒, 非常感谢.
在网上搜了不少方案, 最终选择了参照参考来源1
的文章中的方案3, 进行适当修改以适应当前项目.
最终以用户为单位, 对其请求接口频率进行控制.
逻辑
把限制逻辑封装到一个Lua脚本中,调用时只需传入:key、限制数量、过期时间,调用结果就会指明是否运行访问
lua脚本(这里java字符串对双引号进行了处理)
local notexists = redis.call(\"set\", KEYS[1], 1, \"NX\", \"EX\", tonumber(ARGV[2]))
if (notexists) then
return 1
end
local current = tonumber(redis.call(\"get\", KEYS[1]))
if (current == nil) then
local result = redis.call(\"incr\", KEYS[1])
redis.call(\"expire\", KEYS[1], tonumber(ARGV[2]))
return result
end
if (current >= tonumber(ARGV[1])) then
error(\"too many requests\")
end
local result = redis.call(\"incr\", KEYS[1])
return result
使用 eval 调用脚本
eval 脚本 1 key 参数(允许的最大次数) 参数(过期时间)
正常执行时, redis会返回key对应的数字, 而超过限制后, redis会返回error异常
java代码(部分)
String script = "lua脚本";
String scriptSha = "事先存好的脚本sha"
......
Jedis jedis = JedisPool.getJedisInstance();
if(!jedis.scriptExists(getRedisScriptHash())) {//判断脚本是否存在
scriptSha = jedis.scriptLoad(lua脚本);//写入脚本
}
try {
List<String> keys = new ArrayList<>();
keys.add("判断用户的key");
List<String> args = new ArrayList<>();
args.add("60");//key的存活时间, 60秒
jedis.evalsha(scriptSha, keys, args);
} catch (Exception e) {
System.out.println("请求过于频繁");
......
} finally {
jedis.close();
}