Redis构建分布式锁(加锁、解锁)通用函数

Redis构建分布式锁(加锁、解锁)通用函数

use Util\RedisUtil;
class Index {
function redis()
    {
        $keyname = 'usr';
        $redisObj = new RedisUtil('127.0.0.1', 6379);
        $start = $this->getMillisecond();
        //这里只是模拟瞬间高压力,高并发为多个客户端同时发送请求此redis函数
        for ($i = 0; $i < 1000; $i++) {
            //须加锁确保计数正确,否则高并发下统计会出错(A用户在get的时候,B用户还未及时set)
            $uid = $redisObj->setRedisLock('lockname');
            if ($uid) {
                /*
                $count = $redisObj->get('countname');
                $count = $count +1;
                $redisObj->set('countname',$count);
                */

                /*
                 * 高并发下,可以把用户的请求$_POST['uid'],先存在redis里,再用crontab依次取出
                 * do{}while(),一条一条插入数据库;
                 * */
                $data = array(
                    'id' => $i,
                    'uid' => $uid,
                );
                $redisObj->lpush($keyname, json_encode($data));

                $redisObj->releaseLock('lockname', $uid);
            }

        }

        $end = $this->getMillisecond();
        echo "加入执行时间为:" . ($end - $start) . "ms
"; /* * 可封装为 crontab shell函数,依次取得数据; * 重连redis ,取出数据,关闭连接; * */ echo "取出数据"; $ele = null; do { $ele = $redisObj->rpop($keyname); if ($ele) { echo "get element:" . $ele . "
"; // 插入数据库 //$res = $db->insert('tablename',$ele); // 如果插入数据库失败,则rollover //if (!$res){$redisObj->rPush($keyname,$ele);} } } while ($ele != null); $popTime = $this->getMillisecond(); echo "结束取出时间为:" . ($popTime - $start) . "ms
"; //关闭redis连接; $redisObj->close(); //清空数据 $redisObj->flushDb(); } function getMillisecond() { list($s1, $s2) = explode(' ', microtime()); return (float)sprintf('%.0f', (floatval($s1) + floatval($s2)) * 1000); } }

RedisUtil工具类


class RedisUtil
{

    private $redis = ""; //redis对象

    /**
     * @desc 构造函数
     *
     * @param $host string | redis主机
     * @param $port int    | 端口
     */

    public function __construct($host, $port = 6379)
    {
        $this->redis = new \Redis();
        $this->redis->connect($host, $port);
    }

    /**
     * @desc 加锁方法
     *
     * @param $lockName string | 锁的名字
     * @param $timeout int | 锁的过期时间
     *
     * @return 成功返回identifier/失败返回false
     */
    public function setRedisLock($lockname, $timeout = 2)
    {

        $uid = uniqid(); //唯一ID;
        $timeout = ceil($timeout); //整数;
        $end = time() + $timeout;

        while (time() < $end) {

            //#上锁
            if ($this->redis->setnx($lockname, $uid)) {
                // #为$lockName设置过期时间,防止死锁
                $this->redis->expire($lockname, $timeout);
                //上锁成功,锁2S过期,返回 $id;
                return $uid;
            } else if ($this->redis->ttl($lockname) === -1) {
                // #为$lockName设置过期时间,防止死锁
                // #检测是否有设置过期时间,没有则加上
                // 假设,客户端A上一步没能设置时间就进程奔溃了,
                // 客户端B就可检测出来,并设置时间
                $this->redis->expire($lockname, $timeout);
            }

            //Delay execution in microseconds
            usleep(0.001);//停止0.001ms
        }
        //上锁不成功;
        return false;
    }

    /**
     * @desc 释放锁
     *
     * @param $lockName string   | 锁名
     * @param $identifier string | 锁的唯一值
     *
     * @param bool
     */
    function releaseLock($lockname, $id)
    {
        //#判断是锁有没有被其他客户端修改
        if ($this->redis->get($lockname) === $id) {

            $this->redis->multi();
            //删除锁;
            $this->redis->del($lockname);
            $this->redis->exec();
            return true;

        } else {
            //#其他客户端修改了锁,不能删除别人的锁
            return false;
        }
    }

    /*
     * @set
     * */
    function set($keyname, $val)
    {
        $this->redis->set($keyname, $val);
    }

    /*
     * @get
     * */
    function get($keyname)
    {
        return $this->redis->get($keyname);
    }

    /*
     * @关闭
     * */
    function close()
    {
        $this->redis->close();
    }

    /*
     * @lpush
     * */

    function lpush($keyname,$val){
        $this->redis->lPush($keyname,$val);
    }

    /*
     * @rpush
     * */

    function rpush($keyname,$val){
        $this->redis->rPush($keyname,$val);
    }

    /*
     * @rpop
     * */
    function rpop($keyname){
        return $this->redis->rPop($keyname);
    }

    /*
     * @清空
     * */
    function flushDb()
    {
        $this->redis->flushDB();
    }
}

参考:https://www.cnblogs.com/phpstudy2015-6/p/6575775.html#_label6

你可能感兴趣的:(redis,php)