Cet article parlera des verrous dans Redis et expliquera pourquoi les verrous sont utilisés. Avez-vous vraiment besoin de Redlock (verrou distribué Redis) ?
Pourquoi devrions-nous utiliser des verrous
Dans une entreprise d'enseignement primaire et secondaire pour laquelle je travaillais, nous avons eu un scénario commercial comme celui-ci. Le côté entreprise doit planifier des cours pour les étudiants. Parfois, des commentaires indiquent que les heures de cours de l'étudiant sont clairement suffisantes, mais il est indiqué que les heures de cours sont insuffisantes. Lorsque la page est actualisée, il s'avère que les heures de cours de l'étudiant sont insuffisantes. ne suffit plus. Ce qui est encore plus effrayant, c’est que parfois les heures de cours des étudiants seront déduites en nombres négatifs (les heures de cours de l’entreprise seront utilisées gratuitement). [Recommandations associées : Tutoriel vidéo Redis]
Un autre exemple est le suivant
Les deux problèmes ci-dessus sont tous deux causés par la concurrence dans notre entreprise. La solution principale à ce problème est qu’une seule requête peut être autorisée à lire et écrire ces données sensibles (importantes) en même temps. Par conséquent, des verrous distribués doivent être utilisés à ce stade pour limiter l'exécution simultanée du programme.
Quels sont les problèmes avec setnx
Voyons d'abord comment implémenter des verrous distribués à l'aide de Redis, que tout le monde doit connaître. Par exemple, pour le problème de planification des cours des étudiants mentionné au début de mon article, nous pouvons le verrouiller comme ceci
C'est ainsi que nous utilisons régulièrement setnx pour implémenter le verrouillage.
Supposons maintenant qu’un tel scénario existe. Lorsqu'il a demandé à A d'obtenir le verrou, le programme a raccroché à l'étape 2 lors de la planification des cours pour les étudiants, et le verrou n'a pas été libéré. Le verrou devient alors une impasse, et la prochaine demande visant à faire fonctionner le même étudiant n'obtiendra jamais le verrou, et l'étudiant ne peut pas être planifié. À ce stade, vous devez déverrouiller manuellement le verrou.
Afin de résoudre le problème de blocage, nous ajoutons un délai d'expiration au verrou.
Après avoir ajouté le délai d'expiration, si la demande A ne libère pas activement le verrou, elle sera activement libérée après l'expiration du verrou, afin que la demande B puisse également obtenir la logique métier de traitement du verrou. Mais si le délai d'expiration est ajouté, le programme plante entre les étapes 1 et 2. Il y aura alors toujours un problème de blocage. La racine de ce problème est que les deux instructions setnx et expire ne sont pas des instructions atomiques. Ce serait donc bien si setnx et expire pouvaient les exécuter tous ou aucun d'entre eux.
Pour cette raison, avant Redis2.8, un grand nombre de packages d'extension ont émergé dans la communauté pour résoudre ce problème. Afin de contrôler ce chaos, le responsable a ajouté les paramètres étendus de l'instruction set dans la version 2.8 afin que les instructions setnx et expire puissent être exécutées ensemble, nous utilisons donc maintenant des verrous distribués comme celui-ci
Ça a l'air parfait maintenant, notre attente a été réalisée "Ce serait formidable si setnx et expire pouvaient les exécuter tous ou aucun d'entre eux". Supposons que nous ayons maintenant le scénario suivant :
Une requête obtient désormais le verrou et le délai d'expiration du verrouillage est fixé à 5 secondes. À l'étape 2, la logique métier est exécutée, mais pour une raison quelconque, la logique métier n'a pas été exécutée après 5 secondes. À ce moment, le verrou est automatiquement libéré en raison d'un délai d'attente. À ce moment-là, la demande B est également arrivée et après avoir obtenu le verrou, la logique métier a commencé à être exécutée. À ce stade, la logique métier de la demande de A a été exécutée, la troisième étape est lancée et le verrou est libéré. À ce moment-là, le verrou a été obtenu à la demande de B, mais a été libéré à la demande de A. Ensuite, la requête C peut obtenir le verrou. À ce stade, la requête B et la requête C entraîneront des problèmes de concurrence. Cet exemple montre donc que le réglage du délai d'expiration dans les verrous distribués est très important. Si le délai défini est inférieur au temps de réponse de cette interface, des problèmes de concurrence se produiront toujours. Par conséquent, nous pouvons nous référer à la surveillance du temps de réponse de l'interface pour définir le délai d'expiration du verrouillage.
Redlock
Nos solutions ci-dessus sont toutes basées sur une implémentation Redis en un seul point. La mise en œuvre Redis en un seul point de verrous distribués peut essentiellement répondre à 95 % des scénarios commerciaux. Les 5 % restants sont des scénarios commerciaux qui ont des exigences extrêmement strictes en matière de cohérence des données et ont une tolérance zéro en matière de perte de verrouillage. En ce moment, vous devez considérer Redlock. Quant à Redis à point unique, même s'il garantit une haute disponibilité via Sentinel, si le nœud maître change de maître-esclave pour certaines raisons et si la synchronisation des données maître-esclave n'est pas opportune, une perte de données se produira et une perte de verrouillage se produira. .
Supposons qu'il existe plusieurs instances Redis. Ces nœuds sont complètement indépendants et n'ont pas besoin d'utiliser la réplication ou un quelconque système de coordination des données. Nous supposons qu'il existe 5 nœuds maîtres Redis. les étapes deviendront comme ceci :
Obtenez l'heure actuelle du serveur en millisecondes
Essayez d'utiliser la même clé et la même valeur aléatoire pour acquérir le verrou. Le client doit avoir un délai d'attente pour chaque machine lors de l'acquisition du verrou. Par exemple, le délai d'expiration du verrou est de 10 secondes, puis le délai d'attente pour en acquérir un seul. le verrouillage du nœud doit durer environ 5 à 50 millisecondes. Le but est de garantir que le client ne passe pas de temps supplémentaire à se connecter à la machine défaillante ! Si les données ne sont pas obtenues dans le délai d'expiration, le nœud sera abandonné et le prochain nœud Redis sera obtenu.
Une fois l'acquisition terminée, obtenez l'heure actuelle moins l'heure obtenue à l'étape 1, si et seulement si le client obtient le verrou de plus de la moitié (ici, 3 nœuds) des nœuds Redis et le temps pour obtenir le le verrouillage est inférieur au délai d'expiration du montant du verrouillage, cela prouve que le verrouillage est efficace !
Si la serrure est acquise, le temps de validité réel de la clé est égal au temps de validité moins le temps utilisé pour acquérir la serrure (le résultat calculé à l'étape 3).
Si plus de la moitié des machines qui acquièrent le verrou ne sont pas satisfaites, ou si le délai d'expiration du verrouillage est négatif après calcul, ou d'autres opérations anormales, le système tentera de déverrouiller toutes les instances, même si certaines instances Redis ne sont pas verrouillées avec succès, empêchant certaines instances d'être verrouillées. Certains nœuds acquièrent le verrou mais le client ne reçoit pas de réponse, ce qui fait que le verrou ne peut pas être réacquis pendant un certain temps. Nous pouvons donc voir que le redlock est en fait un plus. verrouillage fiable que Redis à point unique.
que vous pouvez utiliser directement.
Avons-nous vraiment besoin de redlock
Il existe en fait une autre voix à propos de redlock, écrite par Martin Kleppmann (chercheur à l'Université de Cambridge, engagé dans le projet TRVE DATA à l'intersection des bases de données, des systèmes distribués et sécurité de l'information) J'ai déjà publié un
blogsur quelques points de vue sur redlock. Si vous êtes intéressé, vous pouvez le lire. L'auteur de Redis Salvatore a également apporté quelques réponses aux questions de cet article, ce qui est assez intéressant. Les principaux points du blog de l'auteur sont les suivants : Il n'y a pas plus de deux utilisations des verrous distribués :
Efficacité : L'utilisation de verrous peut éviter de faire inutilement deux fois le même travail (comme certains calculs coûteux). Si le verrou échoue et que les deux nœuds finissent par faire le même travail, le résultat est une légère augmentation du coût (vous finissez par payer AWS 5 cents de plus que autrement) ou un inconvénient mineur (par exemple, l'utilisateur finit par recevoir le même e-mail). notification). Correction : l'utilisation de verrous empêche les processus simultanés d'interférer les uns avec les autres et de corrompre l'état du système. Si le verrouillage échoue et que deux nœuds traitent le même élément de données en même temps, le résultat est une corruption de fichiers, une perte de données, une incohérence permanente, une mauvaise dose de médicament administrée au patient ou un autre problème très grave.Le timing et les horloges système font des hypothèses dangereuses et dépendent fortement de l'horloge de chaque serveur. Parce qu'il y a un GC dans le système, l'ensemble du serveur est percuté pendant le GC et le temps stagne, nous ne pouvons donc pas avoir une forte dépendance à l'égard de l'horloge.
Aucun jeton. Le serveur n'émet pas de jeton à chaque fois que le client acquiert le verrou. Le serveur doit vérifier que le jeton du client doit être cohérent avec le jeton actuel du serveur lors de chaque opération pour rendre difficile le fonctionnement du verrou.
L'auteur se concentre principalement sur les points de vue ci-dessus. Si vous êtes intéressé, il est recommandé de lire l'article original.
! !
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!