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['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, ); // 创建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>'; } ?>
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!