欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Redis上實現(xiàn)分布式鎖以提高性能的方案研究

 更新時間:2015年12月07日 16:16:33   作者:Kelly  
這篇文章主要介紹了Redis上實現(xiàn)分布式鎖以提高性能的方案研究,其中重點需要理解異步算法與鎖的自動釋放,需要的朋友可以參考下

背景:

在很多互聯(lián)網(wǎng)產(chǎn)品應用中,有些場景需要加鎖處理,比如:秒殺,全局遞增ID,樓層生成等等。大部分是解決方案基于DB實現(xiàn)的,Redis為單進程單線程模式,采用隊列模式將并發(fā)訪問變成串行訪問,且多客戶端對Redis的連接并不存在競爭關系。

項目實踐

任務隊列用到分布式鎖的情況比較多,在將業(yè)務邏輯中可以異步處理的操作放入隊列,在其他線程中處理后出隊,此時隊列中使用了分布式鎖,保證入隊和出隊的一致性。關于redis隊列這塊的邏輯分析,我將在下一次對其進行總結(jié),此處先略過。


接下來對redis實現(xiàn)的分布式鎖的邏輯代碼進行詳細的分析和理解:

1、為避免特殊原因?qū)е骆i無法釋放, 在加鎖成功后, 鎖會被賦予一個生存時間(通過 lock 方法的參數(shù)設置或者使用默認值), 超出生存時間鎖將被自動釋放.

2、鎖的生存時間默認比較短(秒級, 具體見 lock 方法), 因此若需要長時間加鎖, 可以通過 expire 方法延長鎖的生存時間為適當?shù)臅r間. 比如在循環(huán)內(nèi)調(diào)用 expire
3、系統(tǒng)級的鎖當進程無論因為任何原因出現(xiàn)crash,操作系統(tǒng)會自己回收鎖,所以不會出現(xiàn)資源丟失。
4、但分布式鎖不同。若一次性設置很長的時間,一旦由于各種原因進程 crash 或其他異常導致 unlock 未被調(diào)用,則該鎖在剩下的時間就變成了垃圾鎖,導致其他進程或進程重啟后無法進入加鎖區(qū)域。

<?php
 
require_once 'RedisFactory.php';
 
/**
* 在 Redis 上實現(xiàn)的分布式鎖
*/
class RedisLock {
  
//單例模式
  private static $_instance = null;
  public static function instance() {
    if(self::$_instance == null) {
      self::$_instance = new RedisLock();
    }
    return self::$_instance;
  }
 
  
//redis對象變量
  private $redis;
  
//存放被鎖的標志名的數(shù)組
  private $lockedNames = array();
 
  public function __construct() {
    
//獲取一個 RedisString 實例
    $this->redis = RedisFactory::instance()->getString();
  }
 
  
/** 
  
* 加鎖
  
*
  
* @param string 鎖的標識名
  
* @param int 獲取鎖失敗時的等待超時時間(秒), 在此時間之內(nèi)會一直嘗試獲取鎖直到超時. 為 0 表示失敗后直接返回不等待
  
* @param int 當前鎖的最大生存時間(秒), 必須大于 0 . 如果超過生存時間后鎖仍未被釋放, 則系統(tǒng)會自動將其強制釋放
  
* @param int 獲取鎖失敗后掛起再試的時間間隔(微秒)
  
*/
  public function lock($name, $timeout = 0, $expire = 15, $waitIntervalUs = 100000) {
    if(empty($name)) return false;
 
    $timeout = (int)$timeout;
    $expire = max((int)$expire, 5);
    $now = microtime(true);
    $timeoutAt = $now + $timeout;
    $expireAt = $now + $expire;
 
    $redisKey = "Lock:$name";
    while(true) {
      $result = $this->redis->setnx($redisKey, (string)$expireAt);
      if($result !== false) {
        
//對$redisKey設置生存時間
        $this->redis->expire($redisKey, $expire);
        
//將最大生存時刻記錄在一個數(shù)組里面
        $this->lockedNames[$name] = $expireAt;
        return true;
      }
 
      
//以秒為單位,返回$redisKey 的剩余生存時間
      $ttl = $this->redis->ttl($redisKey);
      
// TTL 小于 0 表示 key 上沒有設置生存時間(key 不會不存在, 因為前面 setnx 會自動創(chuàng)建)
      
// 如果出現(xiàn)這種情況, 那就是進程在某個實例 setnx 成功后 crash 導致緊跟著的 expire 沒有被調(diào)用. 這時可以直接設置 expire 并把鎖納為己用
      if($ttl < 0) {
        $this->redis->set($redisKey, (string)$expireAt, $expire);
        $this->lockedNames[$name] = $expireAt;
        return true;
      }
 
      
// 設置了不等待或者已超時
      if($timeout <= 0 || microtime(true) > $timeoutAt) break;
 
      
// 掛起一段時間再試
      usleep($waitIntervalUs);
    }
 
    return false;
  }
 
  
/**
  
* 給當前鎖增加指定的生存時間(秒), 必須大于 0
  
*
  
* @param string 鎖的標識名
  
* @param int 生存時間(秒), 必須大于 0
  
*/
  public function expire($name, $expire) {
    if($this->isLocking($name)) {
      if($this->redis->expire("Lock:$name", max($expire, 1))) {
        return true;
      }
    }
    return false;
  }
 
  
/**
  
* 判斷當前是否擁有指定名稱的鎖
  
*
  
* @param mixed $name
  
*/
  public function isLocking($name) {
    if(isset($this->lockedNames[$name])) {
      return (string)$this->lockedNames[$name] == (string)$this->redis->get("Lock:$name");
    }
    return false;
  }
 
  
/**
  
* 釋放鎖
  
*
  
* @param string 鎖的標識名
  
*/
  public function unlock($name) {
    if($this->isLocking($name)) {
      if($this->redis->deleteKey("Lock:$name")) {
        unset($this->lockedNames[$name]);
        return true;
      }
    }
    return false;
  }
 
  
/** 釋放當前已經(jīng)獲取到的所有鎖 */
  public function unlockAll() {
    $allSuccess = true;
    foreach($this->lockedNames as $name => $item) {
      if(false === $this->unlock($name)) {
        $allSuccess = false;
      }
    }
    return $allSuccess;
  }
}

此類很多代碼都寫上了注釋,只要認真理解下,就很容易懂得如何在redis實現(xiàn)分布式鎖了。

相關文章

  • 一文帶你了解Redis的三種集群模式

    一文帶你了解Redis的三種集群模式

    Redis?的常用的集群方式主要有以下三種,分別是主從復制模式、哨兵模式、Redis-Cluster集群模式,那么下面我們就分別了解一下這三種集群模式的優(yōu)點與缺點
    2023-06-06
  • redis搭建哨兵集群的實現(xiàn)步驟

    redis搭建哨兵集群的實現(xiàn)步驟

    本文主要介紹了redis搭建哨兵集群的實現(xiàn)步驟,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-05-05
  • Redis數(shù)據(jù)庫安裝部署及基本操作詳解

    Redis數(shù)據(jù)庫安裝部署及基本操作詳解

    這篇文章主要介紹了Redis數(shù)據(jù)庫安裝部署及基本操作,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-08-08
  • Redis有序集合類型的操作_動力節(jié)點Java學院整理

    Redis有序集合類型的操作_動力節(jié)點Java學院整理

    今天通過本文給大家說一下Redis中最后一個數(shù)據(jù)類型 “有序集合類型”,需要的的朋友參考下吧
    2017-08-08
  • Redis中ServiceStack.Redis和StackExchange.Redis區(qū)別詳解

    Redis中ServiceStack.Redis和StackExchange.Redis區(qū)別詳解

    本文主要介紹了Redis中ServiceStack.Redis和StackExchange.Redis區(qū)別詳解,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • Redis sentinel節(jié)點如何修改密碼

    Redis sentinel節(jié)點如何修改密碼

    這篇文章主要介紹了Redis sentinel節(jié)點如何修改密碼問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Redis實現(xiàn)分布式鎖的方法示例

    Redis實現(xiàn)分布式鎖的方法示例

    本篇文章主要介紹了Redis實現(xiàn)分布式鎖的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • Redis分布式鎖一定要避開的兩個坑

    Redis分布式鎖一定要避開的兩個坑

    這篇文章主要為大家詳細介紹了Redis中分布式鎖一定要避開的兩個坑以及對應的解決方法,文中的示例代碼講解詳細,希望對大家有所幫助
    2023-04-04
  • 詳解redis是如何實現(xiàn)隊列消息的ack

    詳解redis是如何實現(xiàn)隊列消息的ack

    這篇文章主要介紹了關于redis是如何實現(xiàn)隊列消息的ack的相關資料,文中介紹的非常詳細,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-04-04
  • Redis實戰(zhàn)之商城購物車功能的實現(xiàn)代碼

    Redis實戰(zhàn)之商城購物車功能的實現(xiàn)代碼

    這篇文章主要介紹了Redis實戰(zhàn)之商城購物車功能的實現(xiàn)代碼,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-02-02

最新評論