(執行個體篇)php 使用redis鎖限制並發訪問類樣本

來源:互聯網
上載者:User

標籤:資料   this   localhost   timeout   ram   不同   測試   網路   exception   

1.並發訪問限制問題

  對於一些需要限制同一個使用者並發訪問的情境,如果使用者並發請求多次,而伺服器處理沒有加鎖限制,使用者則可以多次請求成功。

  例如換領優惠券,如果使用者同一時間並發提交換領碼,在沒有加鎖限制的情況下,使用者則可以使用同一個換領碼同時兌換到多張優惠券。

  虛擬碼如下:

    if A(可以換領)
          B(執行換領)
              C(更新為已換領)
             D(結束)

  如果使用者並發提交換領碼,都能通過可以換領(A)的判斷,因為必須有一個執行換領(B)後,才會更新為已換領(C)。因此如果使用者在有一個更新為已換領之前,有多少次請求,這些請求都可以執行成功。

2.並發訪問限制方法

  使用檔案鎖可以實現並發訪問限制,但對於分布式架構的環境,使用檔案鎖不能保證多台伺服器的並發訪問限制。

  Redis是一個開源的使用ANSI C語言編寫、支援網路、可基於記憶體亦可持久化的日誌型、Key-Value資料庫,並提供多種語言的API。 

  本文將使用其setnx方法實現分布式鎖功能。setnx即Set it N**ot eX**ists。 

  當索引值不存在時,插入成功(擷取鎖成功),如果索引值已經存在,則插入失敗(擷取鎖失敗)

 

2.簡單案例

  RedisLock.class.php

  

 1 <?php 2 /** 3  * Redis鎖操作類 4  * Date:  2016-06-30 5  * Author: fdipzone 6  * Ver:  1.0 7  * 8  * Func: 9  * public lock  擷取鎖10  * public unlock 釋放鎖11  * private connect 串連12  */13 class RedisLock { // class start14  15   private $_config;16   private $_redis;17  18   /**19    * 初始化20    * @param Array $config redis串連設定21    */22   public function __construct($config=array()){23     $this->_config = $config;24     $this->_redis = $this->connect();25   }26  27   /**28    * 擷取鎖29    * @param String $key  鎖標識30    * @param Int   $expire 鎖到期時間31    * @return Boolean32    */33   public function lock($key, $expire=5){34     $is_lock = $this->_redis->setnx($key, time()+$expire);35  36     // 不能擷取鎖37     if(!$is_lock){38  39       // 判斷鎖是否到期40       $lock_time = $this->_redis->get($key);41  42       // 鎖已到期,刪除鎖,重新擷取43       if(time()>$lock_time){44         $this->unlock($key);45         $is_lock = $this->_redis->setnx($key, time()+$expire);46       }47     }48  49     return $is_lock? true : false;50   }51  52   /**53    * 釋放鎖54    * @param String $key 鎖標識55    * @return Boolean56    */57   public function unlock($key){58     return $this->_redis->del($key);59   }60  61   /**62    * 建立redis串連63    * @return Link64    */65   private function connect(){66     try{67       $redis = new Redis();68       $redis->connect($this->_config[‘host‘],$this->_config[‘port‘],$this->_config[‘timeout‘],$this->_config[‘reserved‘],$this->_config[‘retry_interval‘]);69       if(empty($this->_config[‘auth‘])){70         $redis->auth($this->_config[‘auth‘]);71       }72       $redis->select($this->_config[‘index‘]);73     }catch(RedisException $e){74       throw new Exception($e->getMessage());75       return false;76     }77     return $redis;78   }79  80 } // class end81  82 ?>

  demo.php

 1 <?php 2 require ‘RedisLock.class.php‘; 3   4 $config = array( 5   ‘host‘ => ‘localhost‘, 6   ‘port‘ => 6379, 7   ‘index‘ => 0, 8   ‘auth‘ => ‘‘, 9   ‘timeout‘ => 1,10   ‘reserved‘ => NULL,11   ‘retry_interval‘ => 100,12 );13  14 // 建立redislock對象15 $oRedisLock = new RedisLock($config);16  17 // 定義鎖標識18 $key = ‘mylock‘;19  20 // 擷取鎖21 $is_lock = $oRedisLock->lock($key, 10);22  23 if($is_lock){24   echo ‘get lock success<br>‘;25   echo ‘do sth..<br>‘;26   sleep(5);27   echo ‘success<br>‘;28   $oRedisLock->unlock($key);29  30 // 擷取鎖失敗31 }else{32   echo ‘request too frequently<br>‘;33 }34  35 ?>

 

測試方法: 

  開啟兩個不同的瀏覽器,同時在A,B中訪問demo.php 

  如果先訪問的會擷取到鎖 

  輸出 

    get lock success 
    do sth.. 
    success

  另一個擷取鎖失敗則會輸出request too frequently

  保證同一時間只有一個訪問有效,有效限制並發訪問。

  為了避免系統突然出錯導致死結,所以在擷取鎖的時候增加一個到期時間,如果已超過到期時間,即使是鎖定狀態都會釋放鎖,避免死結導致的問題

 

(執行個體篇)php 使用redis鎖限制並發訪問類樣本

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.