使用Redis锁来实现防刷机制,redis并发锁(复制可用)
IT-Pony
2018-06-07 PM
804℃
0条
/**
* 申请全局排他锁
* @param string $name 锁名称
* @param int $ttl 锁失效时间,避免死锁
* @param bool $should_block 是否阻塞,非阻塞锁获取失败即返回,阻塞锁会反复申请直到成功
* @throws GusException
* @return boolean
*/
function acquire_global_lock($name, $ttl, $should_block = true){
if(!is_string($name)){
throw new GusException('全局锁名称必须为字符串');
}
$name = trim($name);
if(empty($name)){
throw new GusException('全局锁名称不能为空');
}
if(!is_int($ttl) || $ttl < 1){
throw new GusException('全局锁生存时间必须为正整数');
}
$lock = "PUAS_GLOBAL_LOCK_{$name}";
while(true){
$expire = time() + $ttl + 1;
$ret = Redis::setnx($lock, $expire);
// 获取失败
if($ret == 0){
// 阻塞锁
$old_expire = Redis::get($lock);
$sleep = $old_expire - time();
if($sleep > 0){
if($should_block){
sleep(rand(1, $sleep));
continue;
} else{
// 非阻塞锁,直接失败
return false;
}
} else{
$new_expire = Redis::getset($lock, time() + $ttl + 1);
if($new_expire != $old_expire){
continue;
}
}
}
// 获取成功
break;
}
// 脚本结束时,释放锁
register_shutdown_function(
function ($expire, $lock){
// 如果锁没过期,主动释放,否则不应释放避免已被其他进程锁定
if(time() < $expire){
Redis::del($lock);
}
}, $expire, $lock);
return true;
}
/**
* 释放全局锁
* @param string $name
*/
function release_global_lock($name){
Redis::del("PUAS_GLOBAL_LOCK_{$name}");
}