php 使用redis鎖限制並發訪問類樣本

來源:互聯網
上載者:User
本文介紹了php 使用redis鎖限制並發訪問類,並詳細的介紹了並發訪問限制方法。

1.並發訪問限制問題

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

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

虛擬碼如下:

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

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

2.並發訪問限制方法

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

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

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

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

RedisLock.class.PHP

<?php/** * Redis鎖操作類 * Date:  2016-06-30 * Author: fdipzone * Ver:  1.0 * * Func: * public lock  擷取鎖 * public unlock 釋放鎖 * private connect 串連 */class RedisLock { // class start   private $_config;  private $_redis;   /**   * 初始化   * @param Array $config redis串連設定   */  public function __construct($config=array()){    $this->_config = $config;    $this->_redis = $this->connect();  }   /**   * 擷取鎖   * @param String $key  鎖標識   * @param Int   $expire 鎖到期時間   * @return Boolean   */  public function lock($key, $expire=5){    $is_lock = $this->_redis->setnx($key, time()+$expire);     // 不能擷取鎖    if(!$is_lock){       // 判斷鎖是否到期      $lock_time = $this->_redis->get($key);       // 鎖已到期,刪除鎖,重新擷取      if(time()>$lock_time){        $this->unlock($key);        $is_lock = $this->_redis->setnx($key, time()+$expire);      }    }     return $is_lock? true : false;  }   /**   * 釋放鎖   * @param String $key 鎖標識   * @return Boolean   */  public function unlock($key){    return $this->_redis->del($key);  }   /**   * 建立redis串連   * @return Link   */  private function connect(){    try{      $redis = new Redis();      $redis->connect($this->_config['host'],$this->_config['port'],$this->_config['timeout'],$this->_config['reserved'],$this->_config['retry_interval']);      if(empty($this->_config['auth'])){        $redis->auth($this->_config['auth']);      }      $redis->select($this->_config['index']);    }catch(RedisException $e){      throw new Exception($e->getMessage());      return false;    }    return $redis;  } } // class end ?>

demo.php

<?phprequire 'RedisLock.class.php'; $config = array(  'host' => 'localhost',  'port' => 6379,  'index' => 0,  'auth' => '',  'timeout' => 1,  'reserved' => NULL,  'retry_interval' => 100,); // 建立redislock對象$oRedisLock = new RedisLock($config); // 定義鎖標識$key = 'mylock'; // 擷取鎖$is_lock = $oRedisLock->lock($key, 10); if($is_lock){  echo 'get lock success<br>';  echo 'do sth..<br>';  sleep(5);  echo 'success<br>';  $oRedisLock->unlock($key); // 擷取鎖失敗}else{  echo 'request too frequently<br>';} ?>

測試方法:

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

如果先訪問的會擷取到鎖

輸出

get lock success
do sth..
success

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

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

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

聯繫我們

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