zoukankan      html  css  js  c++  java
  • redis 分布式锁 PHP

    redis分布式
    1.redis是单线程操作
    2.分布式会出现的问题,死锁
    3.redis分布式(集群)。多台服务器里面都有多个单机redis。然后这些redis之间相互链接。还有查看各个单台服务器之间是否链接成功,也就是心跳检测
    4.在数据方面,他们之间有个锁的问题,叫redis分布式锁

    ## 常规流程

    $redisDb = new Redis('127.0.0.1:6379');
    // 获取redis里面的数据
    $res = $redisDb->LRANGE();
    if(!$res) {
        // 如果数据不存在,则去mysql里面获取
        $mysqlDb = mysqli_connect();
        $res = $mysqlDb->select('*');
        // 获取玩了之后插入redis
        foreach ($res as $k => $v) {
            $redisDb->lPush($v);
        }
    }
    return $res;

    这里会出现一个问题,在获取redis数据的时候,出现抢锁的情况

    改动后的流程

    // 设置redis锁
    $expire = 10;//有效期10秒
    $key = 'lock';//key
    $value = time() + $expire;//锁的值 = Unix时间戳 + 锁的有效期
    
    $redisDb = new Redis('127.0.0.1:6379');
    // 获取数据之前,先获取锁
    $status = true;
    while ($status) {
        $lock = $redisDb->setnx($key,$value);
        if($lock) {
            // 如果锁存在且在有效期内,则循环继续获取
            $value = $redisDb->get($key);
            if($value < time()) {
                // 如果在有效期外则删除当前锁,下次进来的时候就直接获取数据且退出循环
                $redisDb->del($key);
            }
        }else{
            $status = false;
            // 获取redis里面的数据
            $res = $redisDb->LRANGE();
            if(!$res) {
                // 如果数据不存在,则去mysql里面获取
                $mysqlDb = mysqli_connect();
                $res = $mysqlDb->select('*');
                // 获取玩了之后插入redis
                foreach ($res as $k => $v) {
                    $redisDb->lPush($v);
                }
            }
        }
    }

    这里原本就可以是最终的版本,但是看到一些言论说。假设进程1del锁之前崩了。那锁会一直存在,进程2和进程3会同时或得到锁。

    ### 最终版

    // 设置redis锁
    $expire = 10;//有效期10秒
    $key = 'lock';//key
    $value = time() + $expire;//锁的值 = Unix时间戳 + 锁的有效期
    
    $redisDb = new Redis('127.0.0.1:6379');
    // 获取redis里面的数据
    $res = $redisDb->LRANGE();
    if(!$res) {
        $status = true;
        while ($status) {
            //设置锁值为当前时间戳 + 有效期
            $lockValue = time() + $expire;
            /**
             * 创建锁
             * 试图以$lockKey为key创建一个缓存,value值为当前时间戳
             * 由于setnx()函数只有在不存在当前key的缓存时才会创建成功
             * 所以,用此函数就可以判断当前执行的操作是否已经有其他进程在执行了
             * @var [type]
             */
            $lock = $redisDb->setnx($key, $lockValue);
            /**
             * 满足两个条件中的一个即可进行操作
             * 1、上面一步创建锁成功;
             * 2、   1)判断锁的值(时间戳)是否小于当前时间    $redis->get()
             *      2)同时给锁设置新值成功    $redis->getset()
             */
            /**
             * ($redisDb->get($key) < time() && $redisDb->getSet($key, $lockValue) < time() )
             * 这个判断的意思是
             * 先判断第一个进程设定的锁是否过期。($redisDb->get($key) < time()
             * 获取到的第一个进程的锁的值再给他设定一个新的值。看他的旧值是否过期   $redisDb->getSet($key, $lockValue) < time()
             */
            if(!empty($lock) || ($redisDb->get($key) < time() && $redisDb->getSet($key, $lockValue) < time() )) {
                //给锁设置生存时间。setnx是系统上给key第一个锁的过期时间,系统不崩,锁会删除。expire是redis自动给key的一个过期时间,系统即使崩了,锁还是会删除
                $redisDb->expire($key, $expire);
                //***********这里执行业务操作
                // 如果数据不存在,则去mysql里面获取
                $mysqlDb = mysqli_connect();
                $res = $mysqlDb->select('*');
                // 获取玩了之后插入redis
                foreach ($res as $k => $v) {
                    $redisDb->lPush($v);
                }
                //***********并吧数据插入数据库
                //以上程序走完删除锁
                //检测锁是否过期,过期锁没必要删除
                if($redisDb->ttl($key))
                    $redisDb->del($key);
                $status = FALSE;
    
            } else {
                // 如果锁存在,则表示有其他进程在处理,这里等待
                sleep(1);
            }
    
        }
    
    }
    return $res;
  • 相关阅读:
    2019-08-01 Ajax实现从数据库读取表
    2019-08-01 JQuery事件
    2019-07-31 Jquery
    2019-07-30 ThinkPHP文件上传
    2019-07-29 ThinkPHP简单的增删改查
    2017-07-26 ThinkPHP简单使用
    python——虚拟环境之virtualenvwrapper-win(windows10,64位)
    python——虚拟环境之virtualenv(windows10,64位)
    python——python3.6环境搭建(Windows10,64位)
    使用poi进行excel下载
  • 原文地址:https://www.cnblogs.com/chenrunxuan/p/13621799.html
Copyright © 2011-2022 走看看