技術進階:Redis分布式鎖的應用(一)

來源:互聯網
上載者:User
匯入

之前一直在給大家寫docker相關的東西,當然docker的東西也會繼續的寫,在此插一篇《關於Redis分布式鎖的應用》開開葷腥。

背景

同一主機同一進程不同的線程,如何同步訪問一段代碼塊呢?
Java有synchronized

synchronized(this) {}

Golang有sync工具包

var mutex sync.Mutex//加鎖mutexmutex.Lock()do Something···//解鎖mutexmutex.Unlock()

PHP
因為PHP沒有多線程的概念,對PHP而言,普遍的是多進程,PHP的多個多進程之間同步訪問,可以通過檔案鎖來實現。

$fp = fopen("logs/lock.l", "a+");if (flock($fp, LOCK_EX)) {  // 進行排它型鎖定    do something....    flock($fp, LOCK_UN);    // 釋放鎖定} else {    echo "鎖正在被其他程式佔用";}fclose($fp);

不同的語言對於同步訪問的問題,會有不同的解決方案,還可以通過共用記憶體來實現,但是這些解決方案的本質都是通過鎖來保持同步的。
現在企業對外提供的服務,一般都是以叢集的方式來做的,那麼多機之前該怎麼去協同同步呢?答案很簡單,用分布式鎖來解決。
接下來嘗試用Redis實現一個分布式鎖。

加鎖

加鎖的時候,對特定的資源加鎖,例如:秒殺情境為庫存餘額加鎖等等。lockKey就代表庫存,要標識這個鎖的身份,所以就要用一個唯一IDuniqLockValue來標識。如果一個任務過長,我們要設定鎖的到期時間$ttl。

//表示庫存 這把鎖$lockKey = "PRODUCT_LOCK_KEY";//擷取一個唯一ID,來表明這個把鎖是誰加的$uniqLockValue = getUniqueId();//加上一把鎖 setnx 是當key不存在的時候,可以添加成功。$ret = $redis->setnx($lockKey,$uniqLockValue);if($ret){    //加鎖成功 設定到期時間    $ttl = 3; // 單位:s    $redis->expire($lockKey,$ttl);}else{    //表明鎖有其他人在使用}
解鎖

解鎖的邏輯如下:擷取鎖,驗證鎖的身份是否是自己加上的,如果是自己加上的並且沒有到期就解鎖,否則,那就解鎖失敗。

$lockKey = "PRODUCT_LOCK_KEY";$currentTime = time();if(($uniqLockValue == $redis->get($lockKey)) && $redis->ttl($lockKey) <= $currentTime){    $redis->del($key);    return true;}else{    return false;}

範例程式碼:

class RedisLock {       const ORDER_LOCK_KEY_PRE = 'PRODUCET_KEY_LOCK';    //鎖到期時間    const LOCK_KEY_EXPIRE = 5;  //類靜態執行個體    private static $objInstance = null;  // redis服務執行個體    protected $objRedis = null;    private function __construct() {        $this->objRedis = new Redis();    $this->objRedis->connect('127.0.0.1', 6379);    }    public static function getInstance() {        if (is_null(self::$objInstance)) {            self::$objInstance = new self();        }        return self::$objInstance;    }    /**     * 加鎖     * @param $strKey string redis key值     * @return bool     */   public function lock($strKey, $force = true) {        //表示庫存 這把鎖        $lockKey = "PRODUCT_LOCK_KEY";        //擷取一個唯一ID,來表明這個把鎖是誰加的        $uniqLockValue = uniqid();        //加上一把鎖 setnx 是當key不存在的時候,可以添加成功。        $ret = $this->objRedis->setnx($lockKey,$uniqLockValue);        // 如果鎖存在 但是 已經到期了        if($ret || ($this->objRedis->ttl($lockKey) == -2 && $this->objRedis->getSet($lockKey,$uniqLockValue))){          //加鎖成功 設定到期時間            $this->objRedis->expire($lockKey,self::LOCK_KEY_EXPIRE);            return true;        }            return false;    }    /**     * 釋放鎖, 如果指定key則釋放指定key,否則全部釋放     * @param $strKey string     */    public function unLock($strKey = '') {      $lockKey = "PRODUCT_LOCK_KEY";      $currentTime = time();      if(($uniqLockValue == $this->objRedis->get($lockKey)) && $this->objRedis->ttl($lockKey) != -2){          $redis->del($key);          return true;      }else{          return false;      }    }    private function __clone () {    }}

其實這樣實現一把鎖是存在一些問題的,其中的很多操作都不能保證其原子性,在平常的情況下不容易顯現出來,接下來我帶大家再進一步最佳化這把鎖。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.