Heim  >  Artikel  >  Backend-Entwicklung  >  PHP verwendet die Redis-Sperre, um den gleichzeitigen Zugriff einzuschränken. Klassenbeispiel

PHP verwendet die Redis-Sperre, um den gleichzeitigen Zugriff einzuschränken. Klassenbeispiel

高洛峰
高洛峰Original
2016-12-26 14:20:221492Durchsuche

In diesem Artikel wird die Verwendung von Redis-Sperren in PHP zur Begrenzung gleichzeitiger Zugriffsklassen vorgestellt und die Methoden zur gleichzeitigen Zugriffsbeschränkung im Detail vorgestellt.

1. Probleme mit der gleichzeitigen Zugriffsbeschränkung

Für einige Szenarien, in denen der gleichzeitige Zugriff desselben Benutzers eingeschränkt werden muss, wenn der Benutzer mehrere Male gleichzeitig Anfragen stellt, und der Server Für den Prozess gibt es keine Sperrbeschränkungen. Der Benutzer kann mehrere Male erfolgreich anfordern.

Wenn der Benutzer beispielsweise beim Einlösen von Gutscheinen den Einlösungscode gleichzeitig einreicht, kann der Benutzer denselben Einlösungscode verwenden, um mehrere Gutscheine gleichzeitig einzulösen, ohne Einschränkungen zu sperren.

Der Pseudocode lautet wie folgt:

wenn A (kann eingelöst werden)
B (Einlösung wird ausgeführt)
C (aktualisiert, um eingelöst zu werden)
D (Ende)

Wenn Benutzer gleichzeitig Einlösungscodes einreichen, können sie alle als einlösbar (A) beurteilt werden, da eine Einlösung (B) ausgeführt werden muss, bevor sie auf das eingelöste Collar aktualisiert wird ( C). Wenn der Benutzer daher mehrere Anfragen stellt, bevor eine Aktualisierung als eingelöst vorliegt, können diese Anfragen erfolgreich ausgeführt werden.

2. Methode zur gleichzeitigen Zugriffsbeschränkung

Durch die Verwendung von Dateisperren können gleichzeitige Zugriffsbeschränkungen erreicht werden. In Umgebungen mit verteilter Architektur kann die Verwendung von Dateisperren jedoch keine gleichzeitigen Zugriffsbeschränkungen auf mehreren Servern garantieren.

Redis ist eine Open-Source-Schlüsselwertdatenbank vom Protokolltyp, die in der ANSI-C-Sprache geschrieben ist, Netzwerke unterstützt, speicherbasiert und persistent sein kann und APIs in mehreren Sprachen bereitstellt.

In diesem Artikel wird die setnx-Methode verwendet, um die verteilte Sperrfunktion zu implementieren. setnx ist Set it N**ot eX**ists.

Wenn der Schlüsselwert nicht vorhanden ist, ist das Einfügen erfolgreich (die Sperre wurde erfolgreich erworben). Wenn der Schlüsselwert bereits vorhanden ist, schlägt das Einfügen fehl (der Sperrenerwerb schlägt fehl)

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[&#39;host&#39;],$this->_config[&#39;port&#39;],$this->_config[&#39;timeout&#39;],$this->_config[&#39;reserved&#39;],$this->_config[&#39;retry_interval&#39;]);
      if(empty($this->_config[&#39;auth&#39;])){
        $redis->auth($this->_config[&#39;auth&#39;]);
      }
      $redis->select($this->_config[&#39;index&#39;]);
    }catch(RedisException $e){
      throw new Exception($e->getMessage());
      return false;
    }
    return $redis;
  }
 
} // class end
 
?>

demo.php

<?php
require &#39;RedisLock.class.php&#39;;
 
$config = array(
  &#39;host&#39; => &#39;localhost&#39;,
  &#39;port&#39; => 6379,
  &#39;index&#39; => 0,
  &#39;auth&#39; => &#39;&#39;,
  &#39;timeout&#39; => 1,
  &#39;reserved&#39; => NULL,
  &#39;retry_interval&#39; => 100,
);
 
// 创建redislock对象
$oRedisLock = new RedisLock($config);
 
// 定义锁标识
$key = &#39;mylock&#39;;
 
// 获取锁
$is_lock = $oRedisLock->lock($key, 10);
 
if($is_lock){
  echo &#39;get lock success<br>&#39;;
  echo &#39;do sth..<br>&#39;;
  sleep(5);
  echo &#39;success<br>&#39;;
  $oRedisLock->unlock($key);
 
// 获取锁失败
}else{
  echo &#39;request too frequently<br>&#39;;
}
 
?>

Testmethode:

Öffnen Sie zwei verschiedene Browser und greifen Sie gleichzeitig auf demo.php in A und B zu

Wenn Sie zuerst darauf zugreifen, erhalten Sie die Sperre

Ausgabe

Sperre erhalten Erfolg
etwas tun.
Erfolg

Wenn eine weitere Erfassungssperre fehlschlägt, wird die Anforderung zu häufig sein Ausgabe

um sicherzustellen, dass zur gleichen Zeit nur ein Zugriff gültig ist, wodurch der gleichzeitige Zugriff effektiv eingeschränkt wird.

Um Deadlocks durch plötzliche Systemfehler zu vermeiden, wird beim Erwerb der Sperre eine Ablaufzeit hinzugefügt. Wenn die Ablaufzeit abgelaufen ist, wird die Sperre auch im gesperrten Zustand aufgehoben, um Probleme durch Deadlocks zu vermeiden .

Weitere PHP-bezogene Artikel zur Verwendung der Redis-Sperre zur Begrenzung gleichzeitiger Zugriffsklassenbeispiele finden Sie auf der chinesischen PHP-Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn