redis 秒杀 lua 脚本
public function kill2Action()
{
$redis = Singleton::getRedis();
$userId = random_int(1, 100);
$goodsId = $this->getRequest()->getQuery('goodsId',1);
$sha1 = $redis->script('load',$this->getLua());
$res = $redis->evalSha($sha1,array($userId,$goodsId),2);
echo $res?$res:'秒杀尚未开始';
}
public function getLua(){
$luaScript = <<<LUA
local userId = KEYS[1]
local goodsId = KEYS[2]
local qtKey = 'SP'..goodsId..'ID'
local userKey = 'SP'..goodsId..'USER'
local goodsNumber = redis.call('get',qtKey)
if tonumber(goodsNumber) <= 0 then
return "商品库存为空"
end
local userExists = redis.call('sismember',userKey,userId)
if tonumber(userExists) == 1 then
return "当前用户已存在"
end
redis.call('decr',qtKey)
redis.call('sadd',userKey,userId)
return "秒杀成功"
LUA;
return $luaScript;
}
LUA脚本在Redis中的优势
- 将复杂的或者多步的redis操作,写为一个脚本,一次提交给redis执行,减少反复连接redis的次数。提升性能。
- LUA脚本是类似redis事务,有一定的原子性,不会被其他命令插队,可以完成一些redis事务性的操作。
- 但是注意redis的lua脚本功能,只有在Redis 2.6以上的版本才可以使用。
利用lua脚本淘汰用户,解决超卖问题. - redis 2.6版本以后,通过lua脚本解决争抢问题,实际上是redis 利用其单线程的特性,用任务队列的方式解决多任务并发问题。解决例如 2000用户秒杀 800库存 却还剩下600 并发问题