1.计数器限流 (lua脚本版)
<?php
$redis = getRedis();
// KEYS[1] redis的key, ARGV[1] 时间范围, ARGV[2] 限制次数,
$lua = <<<SCRIPT
-- KEYS[1]为空不通过
if (not KEYS[1])
then
return false
end
-- KEYS[1] 自增1
local incr = redis.call('INCR', KEYS[1])
-- redis异常时直接通过
if (incr == false)
then
return true
end
if (incr > tonumber(ARGV[2]))
then
-- 如果大于最大限制次数,判断KEYS[1]的生命周期是否正常
local ttl = redis.call('TTL', KEYS[1])
if (ttl == -1)
then
-- 如果还未设置,则给KEYS[1]设置生命周期为ARGV[1]
redis.call('EXPIRE', KEYS[1], ARGV[1])
end
return false
else
if (incr == 1)
then
-- 第一次执行KEYS[1],给KEYS[1]设置生命周期为ARGV[1]
redis.call('EXPIRE', KEYS[1], ARGV[1])
end
return true
end
SCRIPT;
//给key1限流5秒10次
// EVAL 命令要求你在每次执行脚本的时候都发送一次脚本主体(script body)
//$s = $redis->eval($lua, array('key1', 5, 10),1);
/**
* 可以使用 EVALSHA 来代替 EVAL
* 使用 EVALSHA 命令对脚本进行复用,免去了无谓的带宽消耗
*/
//SCRIPT LOAD :将一个脚本装入脚本缓存,但并不立即运行它
//(可将缓存的值保存在redis里,以后每次只在redis里取出SHA1 校验和)
$rtn = $redis->script('load', $lua);
//给key1限流5秒10次
$s = $redis->evalSha($rtn, ['key1', 5, 10], 1);
var_dump($s, $redis->getLastError());
function getRedis()
{
try{
$redis = new Redis();
$redis->connect('127.0.0.1', 6379, 60);
return $redis;
} catch (\Exception $e) {
echo json(-1,'redis链接失败,请稍后再试');
}
}版权声明:本文为muwenbofx原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。