Redis分布式锁

原理

  1. Redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端对Redis的连接并不存在竞争关系
  2. Redis中可以使用setNx命令实现分布式锁。当且仅当 key 不存在,将 key 的值设为 value。 若给定的 key 已经存在,则 setNx不做任何动作
  3. SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写。
  4. 返回值:设置成功,返回 1 。设置失败,返回 0 。
  5. 使用SETNX命令获取锁,若返回0(key已存在,锁已存在)则获取失败,反之获取成功
  6. 为了防止获取锁后程序出现异常,导致其他线程/进程调用setNx命令总是返回0而进入死锁状态,需要为该key设置一个“合理”的过期时间释放锁,使用DEL命令将锁数据删除

利用Redis实现分布式锁的步骤

1.连接Redis

        在PHP中,连接Redis使用的是PHPRedis扩展,需要安装扩展后才能使用。具体安装方法可以参考官方文档。

2.获取锁

        实现一个获取锁的函数如下:

protected function lock($lock_key, $expire_time = 5)
{
    $redis = new Redis();
    $redis->connect('localhost', 6379); // 连接Redis
    $micro_second = 1000000;
    $timeout = 10 * $micro_second; //等待锁超时时间

    while($timeout >= 0)
    {
        $microtime = microtime(true);
        $timeout -= $micro_second;
        $current_lock_time = $microtime + $expire_time + 1; //锁过期时间

        if($redis->setnx($lock_key, $current_lock_time)) //获取锁成功
        {
            $redis->expire($lock_key, $expire_time); //设置过期时间,防止死锁
            return $current_lock_time;
        }

        //检查锁是否过期
        $lock_time = $redis->get($lock_key);
        if($lock_time < $microtime)
        {
            $new_lock_time = $microtime + $expire_time + 1; //设置新的过期时间
            $old_lock_time = $redis->getset($lock_key, $new_lock_time); //获取旧的过期时间并设置新的过期时间
            if($old_lock_time < $microtime) //锁已经过期,获取锁成功
            {
                $redis->expire($lock_key, $expire_time); //设置过期时间,防止死锁
                return $new_lock_time;
            }
        }

        //等待一段时间后再次尝试获取锁
        usleep(10000); //等待10毫秒
    }

    return false;
}

        该函数的作用是获取指定key的锁,若获取成功,则返回锁的过期时间;若获取失败,则返回false。

3.释放锁

        不论是由于获取锁成功后执行完操作后,还是等待一段时间后获取锁失败,都需要释放锁。实现一个释放锁的函数如下:

protected function unlock($lock_key, $current_lock_time)
{
    $redis = new Redis();
    $redis->connect('localhost', 6379); // 连接Redis
    
    $lock_time = $redis->get($lock_key);
    if($lock_time == $current_lock_time) //判断是否为当前持有锁的客户端
        $redis->del($lock_key); //释放锁
}

注意事项

        1.锁的过期时间要根据实际情况合理设置。如果锁的过期时间太短,可能会导致锁失效或者频繁获取不到锁;如果锁的过期时间太长,可能会导致锁过期时间过长,影响系统性能。

        2.在设置过期时间时,一定要注意防止死锁。如有一个客户端获取到锁之后,由于意外退出或崩溃等原因导致锁没有被释放,就会影响其他客户端获取锁,造成死锁问题。

        3.由于分布式锁的实现依赖于客户端的唯一标识,所以不同客户端需要使用不同的标识,否则可能会导致一个客户端释放其他客户端的锁。在PHP中,可以使用PHP_SESSION_ID或者IP地址/进程ID等作为客户端的唯一标识。

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值