• php redis分布式锁


    一,概念

    在PHP中实现分布式锁通常可以使用数据库、缓存系统(如Redis)或者其他中央存储系统来保证在分布式系统中的数据一致性与同步。秒杀下单、抢红包等等业务场景,都需要用到分布式锁。

    在这里插入图片描述
    常规方案大概有七中
    方案一:SETNX + EXPIRE
    方案二:SETNX + value值是(系统时间+过期时间)
    方案三:使用Lua脚本(包含SETNX + EXPIRE两条指令)
    方案四:SET的扩展命令(SET EX PX NX)
    方案五:SET EX PX NX + 校验唯一随机值,再释放锁
    方案六: 开源框架~Redisson
    方案七:多机实现的分布式锁Redlock
    这里我采用方案三,加锁和根据判断解锁都需要保持原子性,所以使用Lua脚本

    二、代码

    
    
    class RedisLock
    {
        private $redis;
        private $lockKey;
    
        public function __construct($lockKey)
        {
            $this->redis = new Redis();
            $this->redis->connect('127.0.0.1', 6379);
            $this->lockKey = $lockKey;
        }
    
        public function acquireLock()
        {
            // 设置锁的超时时间,防止死锁(在删除锁的时候有可能服务挂了,那这个锁就成了死锁,设置过期时间可以防止死锁)
            $expire = 10;
            // 生成一个唯一的标识符(可能会出现线程A代码未执行完,锁已经过期,这时候另外一个线程B就能拿到了锁,这时线程A执行完毕删除锁,如果没有当前线程唯一标识就会删除掉B已经拿到的锁)
            $identifier = uniqid();
    
            while (!$this->redis->set($this->lockKey, $identifier, ['NX', 'EX' => $expire])) {
                // 如果设置失败,等待一段时间后重试
                usleep(1000);
            }
    
            return $identifier;
        }
    
        public function releaseLock($identifier)
        {
            // 释放锁,检查标识符是否匹配,确保只有持有锁的请求才能释放锁
            //这里的判断和删除锁需要保持原子性,所以使用Lua脚本来删除
            if ($this->redis->eval("if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end", [$this->lockKey, $identifier], 1)) {
                return true;
            }
    
            return false;
        }
    }
    
    // 示例用法
    $lock = new RedisLock('my_resource');
    
    // 尝试获取锁
    $identifier = $lock->acquireLock();
    
    if ($identifier) {
        // 成功获取锁,执行需要同步的操作
    
        // 释放锁
        $lock->releaseLock($identifier);
    } else {
        // 获取锁失败,处理冲突或重试逻辑
        echo "Failed to acquire lock\n";
    }
    
    
  • 相关阅读:
    观察者模式-委托(大话设计模式)C/C++版本
    文档管理软件将办公室的业务模式转变为无纸化远程业务模式,提高员工生产力和保留率
    登录页直接拿 那
    Qt实现将字节数组以hex形式显示到文本框的方法
    一图看懂Hadoop中的MapReduce与Spark的区别:从单机数据系统到分布式数据系统经历了哪些?
    Vue 中Lodop 实现批量打印
    Ubuntu screen命令,使终端在断开或关闭后依然存在
    Mysql中MyISAM和InnoDB 引擎的区别
    请各位编写一下单片机c51代码
    CSS零碎知识点记录
  • 原文地址:https://blog.csdn.net/sang521jia/article/details/139629409