用Redis的set指令实现锁

        本文参考了http://huoding.com/2015/09/14/463

        我们知道,现在的Redis实现加锁的方法比较简单,直接调用Redis的set指令:

$redis->set($key, $random, array('nx', 'ex' => $expire));
        就可以实现。其中$random是个随机值,nx表示如果Redis中不存在$key时,就设置$key,ex表示设置超时,$expire表示超时的值。

        但是,解锁的方法稍微复杂些。

        今天跟同事讨论问题时,发现文章开头的链接中给出的方法仍然有问题,有下面这种情况:

         假设现在有两个进程,分别是A和B。A在执行到:

if ($redis->get($key) == $random) {
    $redis->del($key);
}

中$redis->del($key);之前,恰好$key超时,而假设此时B刚好调用set设置好$key,然后A再执行$redis->del($key);即A把B设置的$key删除掉了。要解决这个问题,只有使用watch/multi/exec来解决,即Redis在某个进程的“事务”中watch某个$key后,在multi和exec之间,如果$key被另外一个进程修改,那么当前进程试图对它的操作无效。

        现在将代码修改为:

$redis->watch($key);
$redis->multi();

if ($redis->get($key) == $random) {
    $redis->del($key);
}

$redis->exec();

        如果A执行完比较操作后,$key刚好超时,B再调用set,那么由于$key的值被修改过,所以$redis->del($key);失效;如果A执行完比较操作后,$key没有超时,这时候B执行set操作是会失败的,从而$redis->del($key)删除的是A之前设置的记录。解决问题。

猜你喜欢

转载自blog.csdn.net/winshining/article/details/51755937