国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

php 使用redis鎖限制并發(fā)訪問類示例

Original 2016-12-24 10:49:48 268
abstract:本文介紹了php 使用redis鎖限制并發(fā)訪問類,并詳細(xì)的介紹了并發(fā)訪問限制方法。1.并發(fā)訪問限制問題對(duì)于一些需要限制同一個(gè)用戶并發(fā)訪問的場景,如果用戶并發(fā)請(qǐng)求多次,而服務(wù)器處理沒有加鎖限制,用戶則可以多次請(qǐng)求成功。例如換領(lǐng)優(yōu)惠券,如果用戶同一時(shí)間并發(fā)提交換領(lǐng)碼,在沒有加鎖限制的情況下,用戶則可以使用同一個(gè)換領(lǐng)碼同時(shí)兌換到多張優(yōu)惠券。偽代碼如下:if A(可以換領(lǐng))  &nbs

本文介紹了php 使用redis鎖限制并發(fā)訪問類,并詳細(xì)的介紹了并發(fā)訪問限制方法。

1.并發(fā)訪問限制問題

對(duì)于一些需要限制同一個(gè)用戶并發(fā)訪問的場景,如果用戶并發(fā)請(qǐng)求多次,而服務(wù)器處理沒有加鎖限制,用戶則可以多次請(qǐng)求成功。

例如換領(lǐng)優(yōu)惠券,如果用戶同一時(shí)間并發(fā)提交換領(lǐng)碼,在沒有加鎖限制的情況下,用戶則可以使用同一個(gè)換領(lǐng)碼同時(shí)兌換到多張優(yōu)惠券。

偽代碼如下:

if A(可以換領(lǐng))
    B(執(zhí)行換領(lǐng))
    C(更新為已換領(lǐng))
D(結(jié)束)

如果用戶并發(fā)提交換領(lǐng)碼,都能通過可以換領(lǐng)(A)的判斷,因?yàn)楸仨氂幸粋€(gè)執(zhí)行換領(lǐng)(B)后,才會(huì)更新為已換領(lǐng)(C)。因此如果用戶在有一個(gè)更新為已換領(lǐng)之前,有多少次請(qǐng)求,這些請(qǐng)求都可以執(zhí)行成功。

2.并發(fā)訪問限制方法

使用文件鎖可以實(shí)現(xiàn)并發(fā)訪問限制,但對(duì)于分布式架構(gòu)的環(huán)境,使用文件鎖不能保證多臺(tái)服務(wù)器的并發(fā)訪問限制。

Redis是一個(gè)開源的使用ANSI C語言編寫、支持網(wǎng)絡(luò)、可基于內(nèi)存亦可持久化的日志型、Key-Value數(shù)據(jù)庫,并提供多種語言的API。 

本文將使用其setnx方法實(shí)現(xiàn)分布式鎖功能。setnx即Set it N**ot eX**ists。 

當(dāng)鍵值不存在時(shí),插入成功(獲取鎖成功),如果鍵值已經(jīng)存在,則插入失?。ǐ@取鎖失?。?/p>

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連接設(shè)定
   */
  public function __construct($config=array()){
    $this->_config = $config;
    $this->_redis = $this->connect();
  }
 
  /**
   * 獲取鎖
   * @param String $key  鎖標(biāo)識(shí)
   * @param Int   $expire 鎖過期時(shí)間
   * @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 鎖標(biāo)識(shí)
   * @return Boolean
   */
  public function unlock($key){
    return $this->_redis->del($key);
  }
 
  /**
   * 創(chuàng)建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

<?php
require 'RedisLock.class.php';
 
$config = array(
  'host' => 'localhost',
  'port' => 6379,
  'index' => 0,
  'auth' => '',
  'timeout' => 1,
  'reserved' => NULL,
  'retry_interval' => 100,
);
 
// 創(chuàng)建redislock對(duì)象
$oRedisLock = new RedisLock($config);
 
// 定義鎖標(biāo)識(shí)
$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>';
}
 
?>

   

測試方法: 

打開兩個(gè)不同的瀏覽器,同時(shí)在A,B中訪問demo.php 

如果先訪問的會(huì)獲取到鎖 

輸出 

get lock success 
do sth.. 
success

另一個(gè)獲取鎖失敗則會(huì)輸出request too frequently

保證同一時(shí)間只有一個(gè)訪問有效,有效限制并發(fā)訪問。

為了避免系統(tǒng)突然出錯(cuò)導(dǎo)致死鎖,所以在獲取鎖的時(shí)候增加一個(gè)過期時(shí)間,如果已超過過期時(shí)間,即使是鎖定狀態(tài)都會(huì)釋放鎖,避免死鎖導(dǎo)致的問題。 

更多關(guān)于php 使用redis鎖限制并發(fā)訪問類示例請(qǐng)關(guān)注PHP中文網(wǎng)(www.miracleart.cn)其它文章!

Release Notes

Popular Entries