Sur la façon dont Redis implémente les verrous distribués

Il existe de nombreuses façons d'implémenter des verrous distribués. Cet article décrit l'utilisation de Redis pour implémenter des verrous distribués. Il existe de nombreux codes sur Internet qui utilisent Redis pour implémenter des verrous distribués, mais ces codes sont plus ou moins problématiques. Cet article rédigera une implémentation et indiquera également quelques points d'attention.

Scènes

Pour faciliter l'explication, voici un scénario de jeu où l'utilisateur A a une hache de montagne d'une valeur de 500 lingots et l'utilisateur B a 800 lingots et veut acheter une hache de montagne A. Ces données sont stockées dans Redis. Vous devez écrire du code pour implémenter avec succès la transaction.

problème

Redis implémente les verrous distribués et doit prendre en compte les problèmes suivants:

  • Le processus qui maintient le verrou provoque la libération automatique du verrou car le temps de fonctionnement est trop long, mais le processus lui-même ne le sait pas et peut même libérer les verrous détenus par d'autres processus par erreur.
  • Un processus détenant un verrou et ayant l'intention d'effectuer une longue opération s'est écrasé, mais d'autres processus qui veulent acquérir le verrou ne savent pas quel processus détient le verrou, ni ne peuvent détecter que le processus qui détient le verrou s'est écrasé et ne peut perdre du temps qu'en vain Attendez que le verrou soit libéré.
  • Une fois le verrou détenu par un processus expiré, plusieurs autres processus tentent d'acquérir le verrou en même temps et tous acquièrent le verrou.

Trois caractéristiques

Pour implémenter une serrure distribuée avec une garantie minimale, trois caractéristiques sont requises

  1. Propriété de sécurité: Exclusif (mutuellement exclusif). À tout moment, un seul client détient le verrou.
  2. Propriété de vitalité A: aucune impasse. Même si le client qui détient le verrou tombe en panne ou si le réseau est partitionné, le verrou peut toujours être acquis.
  3. Propriété de vivacité B: tolérance aux pannes. Tant que la plupart des nœuds Redis sont actifs, le client peut acquérir et libérer le verrou.

commander

Utilisez Redis pour implémenter des verrous distribués, utilisez généralement les commandes SETNX ou SET. SETNX ne peut pas définir l'heure d'expiration en même temps. Si la version utilisée est supérieure ou égale à 2.6.12, vous pouvez utiliser la commande SET, qui peut être utilisée pour réaliser les fonctions de SETNX et EXPIRE de manière atomique. Vous trouverez ci-dessous une brève introduction aux deux commandes

SETNX

Format de la commande: valeur de clé SETNX

Complexité temporelle: O (1)

Remarque: keydéfinissez la valeur value, si elle keyn'existe pas, elle équivaut à la commande SET dans ce cas . Quand cela keyexiste, ne faites rien. SETNXC'est le raccourci " SET IF N OT E X- IST".

valeur de retour

  • 1 Si la clé est définie
  • 0 Si la clé n'est pas définie

ENSEMBLE

Format de la commande: valeur de la clé SET [EX secondes] [PX millisecondes] [NX | XX]

Complexité temporelle: O (1)

Description: définissez la clé keysur la valeur "chaîne" spécifiée. Si la clé a enregistré une valeur, cette opération écrasera directement la valeur d'origine et ignorera le type d'origine. Lorsque la setcommande est exécutée avec succès, le délai d'expiration défini précédemment sera invalide.

Options

À partir de la version 2.6.12, redis a SETajouté une série d'options à la commande:

  • EX secondes -Réglez l'heure d'expiration de la clé, en heures et secondes
  • PX millisecondes - Définit le délai d'expiration de la clé, en millisecondes
  • NX -La valeur de la clé ne sera définie que lorsque la clé n'existe pas
  • XX -Seule la valeur de la clé sera définie lorsque la clé existe

atteindre

SETNX est utilisé ici. Après tout, certaines entreprises peuvent avoir une version inférieure de Redis, qui peut être réalisée en utilisant SETNX, et SET est encore plus sans problème.

code montrer comme ci-dessous:

<?php

function uuid($prefix = '')
{
    
    
    $chars = md5(uniqid(mt_rand(), true));
    $uuid  = substr($chars, 0, 8) . '-';
    $uuid .= substr($chars, 8, 4) . '-';
    $uuid .= substr($chars, 12, 4) . '-';
    $uuid .= substr($chars, 16, 4) . '-';
    $uuid .= substr($chars, 20, 12);
    $ret = $prefix . $uuid;
    return strtoupper($ret);
}

function acquireLock($redis,$lockName, $acquireTime = 10, $lockTime = 10)
{
    
    
    $lockKey    = 'lock:' + $lockName;
    $identifier = uuid('identify');
    $end        = time() + $acquireTime;
    while (time() < $end) {
    
    
        if ($redis->setnx($lockKey, $identifier)) {
    
    
            $redis->expire($lockKey, $lockTime);
            return $identifier;
        } elseif ($redis->ttl($lockKey) == -1) {
    
    
            $redis->expire($lockKey, $lockTime);
        }
        usleep(1000);
    }
    return false;
}


function process(){
    
    
    $redis      = new Redis();
    $lockName = 'market';
    //1.获取锁
    $locked = acquireLock($redis,$lockName);
    if($locked === false){
    
    
        return false;
    }
    //2.进行交易
    //判断A和B是否满足交易条件
    //使用管道,对A和B进行操作

    //3.释放锁
    $releaseRes = releaseLock($redis,$lockName,$locked);
    if($releaseRes === false){
    
    
        return false;
    }
}

function releaseLock($redis,$lockName,$identifier){
    
    
    $lockKey    = 'lock:' + $lockName;
    $redis->watch($lockKey);
    if($redis->get($lockKey) === $identifier){
    
    
        $redis->multi();
        $redis->del($lockKey);
        $redis->exec();
        return true;
    }
    $redis->unwatch();
    return false;
}

La description:

  1. Acquérir la serrure:
    • Créer un identifiant $ unique, cette valeur est utilisée pour déterminer si le verrou est acquis par le client actuel lors de la suppression de la clé, afin de ne pas supprimer les verrous des autres clients
    • La boucle while est utilisée pour continuer à acquérir le verrou pendant un certain temps
    • Si vous pouvez obtenir le verrou, vous pouvez l'obtenir et définir un délai pour éviter que le thread ne se bloque lors de son exécution. Le verrou ne peut jamais être libéré.
    • Si le verrou ne peut pas être acquis avec succès, vérifiez le délai d'expiration du verrou actuel. Si le délai d'expiration n'est pas défini, définissez-le pour empêcher les autres threads de se bloquer immédiatement après l'acquisition du verrou. Aucun délai d'expiration n'est défini
  2. Gérer les affaires
    • Vous devez d'abord déterminer si les deux parties à la transaction remplissent les conditions, car l'ensemble du marché est verrouillé, donc une fois le verrou obtenu, le statut des deux parties ne changera pas.
    • L'utilisation du pipeline peut garantir que l'ensemble de la transaction peut être traitée comme une transaction et que les performances seront meilleures que la transaction utilisant redis
  3. Verrouillage de libération
    • Utilisez la montre pour surveiller la serrure. Une fois la clé modifiée, la transaction qui supprime la clé ne sera pas exécutée
    • Besoin de déterminer si la valeur de la clé est la même que l'identifiant $ enregistré par ce thread, et ce n'est que si elle est cohérente qu'elle peut être supprimée
    • Utilisez des transactions pour supprimer des clés. La raison de l'utilisation des transactions est d'empêcher le verrou d'être acquis par d'autres threads.
    • En cas d'échec, n'oubliez pas de déballer
  4. d'autres problèmes
    • Problème de réentrant: réentrant signifie que le thread peut à nouveau acquérir le verrou. La méthode d'implémentation est relativement simple. Il vous suffit de transmettre l'identifiant lors de l'acquisition deLock pour déterminer si l'identifiant du verrou actuel est cohérent avec celui transmis. S'ils sont cohérents, l'opération peut être effectuée
    • Le thread n'a pas été exécuté, le délai de verrouillage est passé et d'autres threads ont acquis le verrou: une solution à ce problème est de vérifier si le verrou existe ou a été modifié après la moitié du délai d'expiration, s'il n'y a pas de changement. Et le thread fonctionne normalement, prolongez le délai d'expiration

En pensant

Si elle est basée sur une seule instance Redis, en supposant que cette instance unique est toujours disponible, cette méthode est suffisamment sûre.

Mais il y a deux situations particulières auxquelles tout le monde doit prêter attention:

Il existe des conditions de concurrence évidentes dans la structure maître-esclave:

  1. Le client A obtient le verrou du maître
  2. Avant que le maître synchronise le verrou avec l'esclave, le maître tombe en panne.
  3. Le nœud esclave est promu nœud maître
  4. Le client B acquiert un autre verrou pour la même ressource que le client A a déjà acquise. Échec de sécurité!

Dans l'environnement distribué de Redis, il existe N maîtres Redis

Dans ce cas, l' algorithme Redlock peut être utilisé

Pour résumer

Cet article décrit comment utiliser Redis pour implémenter des verrous distribués et écrit une implémentation spécifique et l'analyse associée. Pour utiliser Redis pour implémenter des verrous distribués, de nombreux détails doivent être pris en compte: vous pouvez concevoir des verrous qui répondent à vos besoins en fonction de votre propre fiche métier et faire un compromis entre complexité et sécurité.

Les données

  1. https://www.jianshu.com/p/bb8c6c3113dd
  2. http://redis.cn/topics/distlock.html
  3. http://redis.cn/commands/set.html

Enfin

Si vous aimez mon article, vous pouvez suivre mon compte public (Programmeur Mala Tang)

Revue des articles précédents:

  1. Redis implémente les verrous distribués
  2. Suivi des bogues du code source de Golang
  3. Le principe de réalisation de l'atomicité, de la cohérence et de la durabilité des transactions
  4. Comment exercer votre mémoire
  5. Explication détaillée du processus de demande de CDN
  6. Réflexions sur le développement de carrière des programmeurs
  7. L'histoire du service de blog écrasée
  8. Techniques de mise en cache courantes
  9. Comment se connecter efficacement avec un paiement tiers
  10. Version concise du cadre Gin
  11. Réflexion sur la révision du code
  12. Une brève analyse des verrous et des transactions InnoDB
  13. Éditeur Markdown recommandation-typora

Je suppose que tu aimes

Origine blog.csdn.net/shida219/article/details/107137981
conseillé
Classement