PHP verwendet die Redis-Sperre, um gleichzeitige Zugriffsklassen einzuschränken

黄舟
Freigeben: 2023-03-05 19:22:01
Original
1782 Leute haben es durchsucht


1. Probleme mit der gleichzeitigen Zugriffsbeschränkung


Für einige Szenarien, in denen der gleichzeitige Zugriff durch denselben Benutzer eingeschränkt werden muss, wenn die Benutzer haben viele gleichzeitige Anforderungszeiten und es gibt keine Sperrbeschränkung für die Serververarbeitung, und Benutzer können mehrere Male erfolgreich Anforderungen stellen.

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:

if A(可以换领)
    B(执行换领)
    C(更新为已换领)D(结束)
Nach dem Login kopieren
Nach dem Login kopieren

Wenn Benutzer gleichzeitig Einlösecodes einreichen, werden alle das Urteil fällen, dass sie einlösen können (A), weil Es muss eine Ausführung erfolgen. Nach dem Einlösen (B) wird es auf eingelöst (C) aktualisiert. 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 nicht die Sicherheit mehrerer Server gewährleisten. Gleichzeitige Zugriffsbeschränkungen.

Redis ist eine Open-Source-Protokoll-Schlüsselwertdatenbank, die in der Sprache ANSI C 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 es Nnicht eXist.
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?>
Nach dem Login kopieren

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;;
}?>
Nach dem Login kopieren



Testmethode:
Öffnen Sie zwei verschiedene Browser und greifen Sie gleichzeitig auf demo.php in A und B zu
Wenn Sie zuerst darauf zugreifen, wird die Sperre erhalten
Ausgabe
Sperre erfolgreich erhalten
etwas tun.
Erfolgreich sein

Wenn ein anderer die Sperre nicht erhalten kann, wird Anfrage zu häufig ausgegeben

Um sicherzustellen, dass nur ein Zugriff gleichzeitig gültig ist, beschränken Sie den gültigen gleichzeitigen Zugriff.


Um einen Deadlock 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 ein Deadlock-Problem zu vermeiden.


Quellcode-Download-Adresse: Zum Anzeigen klicken

1. Probleme mit gleichzeitigen Zugriffsbeschränkungen

Für einige Benutzer, die dies benötigen Parallelität begrenzen Wenn der Benutzer im Zugriffsszenario mehrere gleichzeitige Anforderungen stellt und der Serverprozess keine Sperrbeschränkungen hat, kann der Benutzer mehrere erfolgreiche Anforderungen stellen.

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:

if A(可以换领)
    B(执行换领)
    C(更新为已换领)D(结束)
Nach dem Login kopieren
Nach dem Login kopieren

Wenn Benutzer gleichzeitig Einlösecodes einreichen, werden alle das Urteil fällen, dass sie einlösen können (A), weil Es muss eine Ausführung erfolgen. Nach dem Einlösen (B) wird es auf eingelöst (C) aktualisiert. 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 nicht die Sicherheit mehrerer Server gewährleisten. Gleichzeitige Zugriffsbeschränkungen.

Redis ist eine Open-Source-Protokoll-Schlüsselwertdatenbank, die in der Sprache ANSI C 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 es Nnicht eXist.
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?>
Nach dem Login kopieren

demo.php

<?phprequire &#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;;
}?>
Nach dem Login kopieren



Testmethode:
Öffnen Sie zwei verschiedene Browser und greifen Sie gleichzeitig auf demo.php in A und B zu
Wenn Sie zuerst darauf zugreifen, wird die Sperre erhalten
Ausgabe
Sperre erfolgreich erhalten
etwas tun.
Erfolg haben

Wenn ein anderer die Sperre nicht erhalten kann, wird eine Anfrage zu häufig ausgegeben

Um sicherzustellen, dass nur ein Zugriff gleichzeitig gültig ist, beschränken Sie den gültigen gleichzeitigen Zugriff.


Um einen Deadlock 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 ein Deadlock-Problem zu vermeiden.


Das Obige ist der Inhalt von PHP, der die Redis-Sperre verwendet, um den gleichzeitigen Zugriff einzuschränken. Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website (www.php .cn)!


Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
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
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!