Maison  >  Article  >  cadre php  >  Comment implémenter des verrous distribués dans Swoole

Comment implémenter des verrous distribués dans Swoole

PHPz
PHPzoriginal
2023-06-25 16:45:21954parcourir

Avec le développement d'Internet et de l'Internet mobile, la concurrence élevée et les systèmes distribués sont devenus des problèmes inévitables dans le développement quotidien. Dans ce cas, les verrous distribués deviennent un outil indispensable qui peut nous aider à éviter des problèmes tels que la concurrence entre les ressources et l’incohérence des données. Cet article explique comment implémenter des verrous distribués dans Swoole pour vous aider à mieux résoudre les problèmes de concurrence dans les systèmes distribués.

1. Qu'est-ce qu'un verrou distribué ?

Dans un système distribué, plusieurs processus accèdent aux ressources partagées en même temps. Afin de garantir que les données ne soient pas endommagées ou que des conflits de concurrence ne se produisent, ces ressources partagées doivent être verrouillées. Le verrou distribué est un mécanisme de verrouillage conçu pour permettre l'utilisation correcte des ressources partagées dans un système distribué.

La mise en œuvre des verrous distribués est relativement complexe. Généralement, les aspects suivants doivent être pris en compte :

  1. Exclusivité mutuelle : un seul processus ou thread peut l'occuper. en même temps Verrouiller
  2. Réentrée : le même processus ou fil peut demander un verrouillage plusieurs fois, mais le même nombre d'opérations de déverrouillage est requis lors du déverrouillage
  3. Prévenir ; blocage : lors de l'acquisition d'un verrou, vous devez définir un délai d'expiration pour éviter une attente infinie due à des exceptions ou à d'autres raisons
  4. Haute disponibilité : vous devez prendre en compte des problèmes tels que les pannes de nœuds, les partitions réseau, etc.;
  5. Performance : Nécessité d'obtenir des fonctionnalités de concurrence élevée et de faible latence.

2. Introduction à Swoole

Swoole est un moteur de communication réseau asynchrone et parallèle hautes performances pour le langage PHP. Côté serveur et côté client de divers protocoles tels que WebSocket. Les fonctionnalités de Swoole incluent :

  1. Hautes performances : utilisation d'un modèle d'E/S asynchrone non bloquant, qui peut considérablement améliorer la capacité de concurrence du serveur
  2. Built- ; en coroutine : peut être facilement implémenté Programmation asynchrone, pas besoin de créer manuellement des threads ou des processus ;
  3. Serveur HTTP/WebSocket intégré : peut facilement implémenter le développement d'applications Web ; Prend en charge MySQL, Redis, ElasticSearch, etc. asynchrones couramment utilisés. Encapsulation d'outils.
  4. Par conséquent, Swoole a une très bonne adaptabilité et peut être utilisé pour construire des systèmes distribués à haute concurrence et hautes performances.

3. Comment implémenter des verrous distribués dans Swoole ?

Ci-dessous, nous présenterons comment implémenter des verrous distribués dans Swoole.

Implémentation de verrous distribués basés sur Redis
  1. Redis est une base de données clé-valeur basée sur la mémoire et l'outil le plus couramment utilisé dans les systèmes distribués. . Il prend en charge une variété de structures de données, notamment des chaînes, des listes, des ensembles, des ensembles ordonnés, etc. Parmi eux, le type chaîne peut être utilisé pour implémenter des verrous distribués.

Le processus général d'utilisation de Redis pour implémenter des verrous distribués est le suivant :

(1) Obtenez un objet de connexion Redis via le pool de connexion Redis

(2) ) Utilisez la commande SETNX Pour réaliser l'exclusivité mutuelle du verrou, lorsque la valeur de retour est 1, cela signifie que l'occupation est réussie

(3) Afin d'éviter un blocage, définissez le délai d'expiration du verrou # ; 🎜🎜# (4) Utilisez la commande DEL pour déverrouiller le verrou.

Ce qui suit est le code d'implémentation spécifique :

class RedisLock
{
    private $redis;

    public function __construct($config)
    {
        $this->redis = new Redis();
        $this->redis->connect($config['host'], $config['port'], $config['timeout']);
        if (!empty($config['auth'])) {
            $this->redis->auth($config['auth']);
        }
    }

    public function lock($key, $timeout = 10)
    {
        $startTime = time();
        do {
            $result = $this->redis->setnx($key, time() + $timeout);
            if ($result) {
                return true;
            }
            $lockTime = $this->redis->get($key);
            if ($lockTime && $lockTime < time()) {
                $oldTime = $this->redis->getset($key, time() + $timeout);
                if ($oldTime == $lockTime) {
                    return true;
                }
            }
            usleep(100); // 100毫秒等待
        } while (time() - $startTime < $timeout);
        return false;
    }

    public function unlock($key)
    {
        $this->redis->del($key);
    }
}

Dans le code ci-dessus, la fonction de verrouillage utilise une boucle do-while pour attendre que le verrou soit libéré lorsque le. le temps d'attente dépasse le délai indiqué. Lorsque le délai d'attente se produit, false est renvoyé ; la commande DEL est utilisée dans la fonction de déverrouillage pour libérer le verrou. Bien que cette méthode soit simple à mettre en œuvre et entraîne une faible surcharge, elle présente également une certaine probabilité de blocage.

Implémentation de verrous distribués basés sur Zookeeper

  1. Zookeeper est un système de coordination distribué et open source qui peut être utilisé pour implémenter des systèmes distribués Synchronisation des données, gestion de la configuration et autres fonctions. Le nœud séquentiel temporaire (EPHEMERAL_SEQUENTIAL) qu'il fournit peut facilement implémenter des verrous distribués.
Le processus général d'utilisation de Zookeeper pour implémenter des verrous distribués est le suivant :

(1) Créez un client Zookeeper et connectez-vous au serveur Zookeeper ; ) Utiliser createSequential La fonction crée un nœud séquentiel temporaire ;

(3) Récupère tous les nœuds dans Zookeeper et les trie par numéro de série de nœud

(4) Compare son propre numéro de série de nœud avec le numéro de série de ; le plus petit nœud actuel, s'ils sont égaux, alors indique que le verrou a été obtenu, sinon il écoutera le dernier nœud avec un numéro de série plus petit que le sien

(5) Lorsqu'un nœud avec un numéro de série plus petit ; Un numéro supérieur au sien est supprimé, le nœud actuel reçoit une notification d'événement, puis répète la quatrième étape.

Ce qui suit est le code d'implémentation spécifique :

class ZookeeperLock
{
    private $zk;
    private $basePath = '/lock';
    private $myNode;

    public function __construct($config)
    {
        $this->zk = new Zookeeper();
        $this->zk->connect($config['host'] . ':' . $config['port']);
        if (isset($config['auth'])) {
            $this->zk->addAuth('digest', $config['auth']);
        }
        if (!$this->zk->exists($this->basePath)) {
            $this->zk->create($this->basePath, null, array(array('perms' => Zookeeper::PERM_ALL, 'scheme' => 'world', 'id' => 'anyone')), null);
        }
    }

    public function lock()
    {
        $this->myNode = $this->zk->create($this->basePath . '/node_', null, array(array('perms' => Zookeeper::PERM_ALL, 'scheme' => 'world', 'id' => 'anyone')), Zookeeper::EPHEMERAL | Zookeeper::SEQUENCE);
        while (true) {
            $children = $this->zk->getChildren($this->basePath);
            sort($children);
            $pos = array_search(basename($this->myNode), $children);
            if ($pos === 0) {
                return true;
            } else {
                $this->zk->exists($this->basePath . '/' . $children[$pos - 1], function ($event_type, $s, $event_data) {
                    $this->unlock();
                });
                usleep(100); // 100毫秒等待
            }
        }
    }

    public function unlock()
    {
        if ($this->myNode) {
            $this->zk->delete($this->myNode);
            $this->myNode = null;
        }
    }
}

Dans le code ci-dessus, la fonction de verrouillage utilise une boucle while pour surveiller le nœud le plus récent avec un numéro de série plus petit que son propre, et lorsque le nœud est supprimé, indiquant qu'il a acquis le verrou ; la fonction de déverrouillage utilise la fonction de suppression pour supprimer le nœud actuel.

Summary

    Cet article présente comment implémenter des verrous distribués dans Swoole, dans lequel nous introduisons deux implémentations couramment utilisées basées sur la méthode Redis et Zookeeper , et le code d'implémentation est donné. En tant que moyen technique important pour garantir la cohérence des données dans les systèmes distribués, les verrous distribués peuvent nous aider à éviter des problèmes tels que les conflits de concurrence et les incohérences des données. Lors de la mise en œuvre de verrous distribués, vous devez prendre en compte des problèmes tels que l'exclusivité mutuelle, la réentrance, la prévention des interblocages, la haute disponibilité et les performances, et choisir différentes méthodes de mise en œuvre en fonction de scénarios d'application réels.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn