Heim > Backend-Entwicklung > PHP-Tutorial > Verwendung von Redis in PHP zur Implementierung einer intelligenten Umschaltung verteilter Sperren

Verwendung von Redis in PHP zur Implementierung einer intelligenten Umschaltung verteilter Sperren

王林
Freigeben: 2023-05-22 10:04:01
Original
915 Leute haben es durchsucht

Da in einem verteilten System mehrere Knoten gleichzeitig auf derselben Ressource arbeiten, besteht die Gefahr von Parallelitätskonflikten. Um dieses Problem zu lösen, verwenden wir normalerweise verteilte Sperren, um den Zugriff auf gemeinsam genutzte Ressourcen zu steuern. Redis ist ein effizienter verteilter Cache, der zur Implementierung verteilter Sperren verwendet werden kann. In diesem Artikel wird erläutert, wie Sie Redis in PHP verwenden, um verteilte Sperren zu implementieren und intelligentes Switching zu realisieren.

1. Was ist eine verteilte Sperre?

Verteilte Sperre bedeutet, dass beim Zugriff mehrerer Knoten auf gemeinsam genutzte Ressourcen nur ein Knoten die Ressource bedienen kann und andere Knoten warten müssen. Verteilte Sperren umfassen zwei Vorgänge: das Erlangen von Sperren und das Freigeben von Sperren. Der Vorgang zum Erlangen der Sperre muss die Thread-Sicherheit gewährleisten und einen wiederholten Erwerb der Sperre vermeiden. Der Vorgang zum Aufheben der Sperre muss sicherstellen, dass die Sperre korrekt aufgehoben wird, um einen Deadlock zu verhindern.

2. Verwenden Sie Redis, um verteilte Sperren zu implementieren

Redis ist eine In-Memory-Datenbank, die schnell auf Daten zugreifen kann und die Verteilung unterstützt. In Redis können Sie den Befehl set verwenden, um den Schlüssel und den Wert festzulegen. Wenn der Schlüssel nicht vorhanden ist, kann die Einstellung erfolgreich sein. Mit dieser Funktion können verteilte Sperren implementiert werden.

Die konkrete Umsetzung kann in zwei Schritte unterteilt werden. Der erste Schritt besteht darin, die Sperre zu erwerben. Wenn die Einstellung erfolgreich ist, bedeutet dies, dass die Sperre von anderen Knoten erworben wurde. Der zweite Schritt besteht darin, die Sperre aufzuheben und den Schlüssel mit dem Befehl del zu löschen.

Das Folgende ist ein PHP-Beispielcode, der Redis verwendet, um verteilte Sperren zu implementieren:

class RedisLock{
    protected $redis;
    protected $lockKey = 'distributed_lock';
    protected $timeout = 30; // 默认锁超时时间30s

    function __construct(){
        $this->redis = new Redis();
        $this->redis->connect('127.0.0.1', 6379);
    }

    function getRedisClient(){
        return $this->redis;
    }

    function setLock($key = ''){
        if(empty($key)){
            $key = $this->lockKey;
        }else{
            $key = $this->lockKey . '_' . $key; // 如果有传入锁键名,则拼接上前缀方便管理
        }

        $timeout = $this->timeout;

        while ($timeout > 0) { // 如果锁未超时,则等待获取锁
            $result = $this->redis->set($key, time() + $timeout, ['nx', 'ex' => $timeout]);

            if ($result){
                return true;
            }

            sleep(1); // 每次等待1秒钟
            $timeout = $timeout -1;
        }

        return false;
    }

    function unlock($key = ''){
        if(empty($key)){
            $key = $this->lockKey;
        }else{
            $key = $this->lockKey . '_' . $key; // 如果有传入锁键名,则拼接上前缀方便管理
        }

        return $this->redis->del($key);
    }
}
Nach dem Login kopieren

Mit dieser Klasse können Sie ganz einfach Sperren erhalten:

$lock = new RedisLock();
if($lock->setLock()){
    // 执行需要获得锁的操作
    $lock->unlock();
}
Nach dem Login kopieren

3. Implementierung einer intelligenten Sperrumschaltung

Die obige Implementierung einer verteilten Sperre ist relativ einfach, aber wenn ein Knotenfehler auftritt, führt dies zu Problemen. Beispiel: Knoten A erhält die Sperre, stellt jedoch während des Betriebs einen Fehler fest, der dazu führt, dass die Sperre nicht normal aufgehoben werden kann. Zu diesem Zeitpunkt versucht Knoten B, die Sperre zu erwerben, schlägt jedoch fehl, da Knoten A die Sperre immer noch hält . Um dieses Problem zu lösen, können wir eine intelligente Sperrumschaltung implementieren.

Zunächst müssen wir einen Mechanismus zum Zurücksetzen des Sperrzeitlimits implementieren, dh nach Ablauf des Sperrzeitlimits wird die Sperre auf einen verfügbaren Status zurückgesetzt. Dies kann durch eine geplante Aufgabe erreicht werden. Zweitens müssen wir den Schlosshalter aufzeichnen. Wenn eine ungewöhnliche Situation auftritt, kann das Schloss des Halters manuell gelöst werden. Schließlich müssen wir einen Sperrwechselmechanismus implementieren. Das heißt, wenn der Knoten, der die Sperre hält, ausfällt, können andere Knoten automatisch zum Sperrhalter wechseln.

Informationen zur spezifischen Implementierung finden Sie im folgenden Beispielcode:

class RedisLock {
    protected $redis;
    protected $lockKey = 'distributed_lock';
    protected $timeout = 30; // 默认锁超时时间30s

    // 锁的持有者
    protected $holder;

    // 获取锁的时间戳,用于超时释放锁
    protected $lockTime;

    function __construct(){
        $this->redis = new Redis();
        $this->redis->connect('127.0.0.1', 6379);
    }

    function getRedisClient(){
        return $this->redis;
    }

    function setLock($key = ''){
        if(empty($key)){
            $key = $this->lockKey;
        }else{
            $key = $this->lockKey . '_' . $key; // 如果有传入锁键名,则拼接上前缀方便管理
        }

        $timeout = $this->timeout;

        // 检查锁是否已被其他节点持有
        if($lockTime = $this->redis->get($key)){
            // 计算锁的剩余时间
            $remainTime = $lockTime + $timeout - time();

            // 如果锁剩余时间大于0,则表示其他节点持有锁
            if($remainTime > 0){
                return false;
            }
        }

        // 尝试获取锁
        $result = $this->redis->set($key, time() + $timeout, ['nx', 'ex' => $timeout]);

        if ($result){
            $this->holder = $key;
            $this->lockTime = time() + $timeout;

            return true;
        }

        return false;
    }

    function unlock($key = ''){
        if(empty($key)){
            $key = $this->lockKey;
        }else{
            $key = $this->lockKey . '_' . $key; // 如果有传入锁键名,则拼接上前缀方便管理
        }

        if($this->holder != $key){
            return false;
        }

        return $this->redis->del($key);
    }

    // 定时任务,每隔一段时间检查锁的持有者是否存活,如果不存活,则尝试切换为当前节点
    function timeoutReset(){
        while(true){
            if(time() > $this->lockTime){
                $this->redis->set($this->holder, '', ['nx', 'ex' => 1]);
            }

            $this->holder = $this->redis->get($this->lockKey);

            if(!$this->holder){
                $this->setLock();
            }

            sleep(1); // 每个一秒执行一次
        }
    }
}
Nach dem Login kopieren

Das Obige implementiert die intelligente Sperrumschaltung. Wenn Knoten A ausfällt, wechseln andere Knoten automatisch zum Sperrhalter, nachdem die Sperre abgelaufen ist. Dieser Mechanismus gewährleistet die hohe Verfügbarkeit und Zuverlässigkeit verteilter Sperren.

4. Zusammenfassung

In diesem Artikel wird erläutert, wie Sie mit Redis verteilte Sperren und einen intelligenten Sperrschaltmechanismus implementieren. Diese Lösung gewährleistet die hohe Verfügbarkeit und Zuverlässigkeit verteilter Sperren und kann in verteilten Systemen häufig eingesetzt werden. Gleichzeitig kann diese Lösung auch zur Lösung anderer Probleme verwendet werden, die Sperrmechanismen erfordern, z. B. Datenbank-Lese-/Schreibsperren, verteilte Transaktionen usw.

Das obige ist der detaillierte Inhalt vonVerwendung von Redis in PHP zur Implementierung einer intelligenten Umschaltung verteilter Sperren. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

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