基於redis的分布式鎖


 

<?php
/**
 * 基於redis的分布式鎖
 *
 * 參考開源代碼:
 * http://nleach.com/post/31299575840/redis-mutex-in-php
 *
 * https://gist.github.com/nickyleach/3694555
 */
pc_base::load_sys_class('cache_redis', '', 0);


class dist_key_redis {

    //鎖的超時時間
    const TIMEOUT = 20;

    const SLEEP = 100000;

    /**
     * Stores the expire time of the currently held lock
     * 當前鎖的過期時間
     * @var int
     */
    protected static $expire;

    public static function getRedis()
    {
        return new cache_redis();
    }

    /**
     * Gets a lock or waits for it to become available
     * 獲得鎖,如果鎖被占用,阻塞,直到獲得鎖或者超時
     *
     * 如果$timeout參數為0,則立即返回鎖。
     * 
     * @param  string    $key        
     * @param  int        $timeout    Time to wait for the key (seconds)
     * @return boolean    成功,true;失敗,false
     */
    public static function lock($key, $timeout = null){
        if(!$key)
        {
            return false;
        }
 
        $start = time();

        $redis = self::getRedis();
 
        do{
            self::$expire = self::timeout();
            
            if($acquired = ($redis->setnx("Lock:{$key}", self::$expire)))
            {
                break;
            }

            if($acquired = (self::recover($key)))
            {
                break;
            }
            if($timeout === 0) 
            {
                //如果超時時間為0,即為
                break;
            }
 
            usleep(self::SLEEP);

        } while(!is_numeric($timeout) || time() < $start + $timeout);
 
        if(!$acquired)
        {
            //超時
            return false;
        }
 
        return true;
    }
 
    /**
     * Releases the lock
     * 釋放鎖
     * @param  mixed    $key    Item to lock
     * @throws LockException If the key is invalid
     */
    public static function release($key){
        if(!$key)
        {
            return false;
        }

        $redis = self::getRedis();
 
        // Only release the lock if it hasn't expired
        if(self::$expire > time()) 
        {
            $redis->del("Lock:{$key}");
        }
    }
 
    /**
     * Generates an expire time based on the current time
     * @return int    timeout
     */
    protected static function timeout(){
        return (int) (time() + self::TIMEOUT + 1);
    }
 
    /**
     * Recover an abandoned lock
     * @param  mixed    $key    Item to lock
     * @return bool    Was the lock acquired?
     */
    protected static function recover($key){

        $redis = self::getRedis();

        if(($lockTimeout = $redis->get("Lock:{$key}")) > time())
        {
            //鎖還沒有過期
            return false;
        }
 
        $timeout = self::timeout();
        $currentTimeout = $redis->getset("Lock:{$key}", $timeout);
 
        if($currentTimeout != $lockTimeout)
        {
            return false;
        }
 
        self::$expire = $timeout;
        return true;
    }
}

?>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM