Redis est un système open source de mise en cache de données en mémoire qui peut stocker et lire des données. Dans un environnement distribué, lorsque plusieurs applications fonctionnent simultanément sur la même ressource, des problèmes de données sales et d'incohérence des données peuvent survenir. Afin de résoudre ce problème, nous pouvons introduire des verrous distribués pour garantir la cohérence des données.
Cet article aide les lecteurs à comprendre comment utiliser Redis pour implémenter des verrous distribués en présentant les scénarios d'application, les principes et les méthodes de mise en œuvre des verrous distribués Redis.
1. Scénarios d'application
Dans un système distribué, une application peut devoir exploiter plusieurs ressources en même temps. Alors, comment garantir que les opérations de cette application sur les ressources sont thread-safe ? À l’heure actuelle, des verrous distribués doivent être introduits.
Les verrous distribués peuvent être utilisés pour résoudre les problèmes suivants :
(1) Évitez que plusieurs clients ne modifient la même ressource en même temps, ce qui entraînerait une incohérence des données.
(2) Évitez que le client apporte plusieurs modifications à la même ressource en raison de retards du réseau et d'autres problèmes.
(3) Évitez que les clients n'occupent les ressources pendant trop longtemps, ce qui empêcherait les autres clients d'accéder normalement aux ressources.
2.Principe
Le verrouillage distribué Redis est principalement implémenté via la commande setnx. La commande setnx est une opération atomique dans Redis, qui garantit que dans les opérations simultanées de plusieurs clients, un seul client peut définir avec succès la paire clé-valeur sur Redis.
Ensuite, jetons un coup d'œil à l'implémentation spécifique du verrouillage distribué Redis.
3. Méthode de mise en œuvre
(1) Obtenir le verrou
Dans le processus d'acquisition du verrou, nous devons utiliser la commande setnx pour définir une paire clé-valeur. Si le réglage réussit, cela signifie que nous avons obtenu le verrou. Si le réglage échoue, nous devons attendre un certain temps et essayer d'obtenir à nouveau le verrou.
Tout d'abord, nous obtenons le verrou grâce au bloc de code suivant :
boolean lock = jedis.setnx(key, value) == 1;
Parmi eux, la clé et la valeur représentent respectivement le nom et la valeur du verrou, et jedis représente le client Redis.
Si le nom du verrou n'existe pas dans Redis, alors la valeur de retour du code ci-dessus est 1, indiquant que le réglage est réussi et que le verrou est obtenu. Si le nom du verrou existe déjà dans Redis, la valeur de retour du code ci-dessus est 0, indiquant que le paramètre a échoué et que l'acquisition du verrou a échoué.
(2) Libérer le verrou
Dans le processus de libération du verrou, nous devons utiliser la commande del pour supprimer les paires clé-valeur dans Redis.
Tout d'abord, nous libérons le verrou via le bloc de code suivant :
long result = jedis.del(key);
Parmi eux, key représente le nom du verrou, et jedis représente le client Redis.
Si la paire clé-valeur dans Redis est supprimée avec succès, la valeur de retour du code ci-dessus est 1, indiquant que le verrou est libéré avec succès. Si la paire clé-valeur n'existe pas dans Redis, la valeur de retour du code ci-dessus est 0, indiquant que le déverrouillage échoue.
(3) Définir le délai d'expiration du verrou
Afin d'éviter que le verrou ne soit occupé tout le temps, nous devons définir le délai d'expiration du verrou. Lorsque le détenteur du verrou ne libère pas le verrou dans un certain laps de temps, Redis supprimera automatiquement le verrou pour éviter qu'il ne soit occupé pour toujours.
Tout d'abord, nous devons définir le délai d'expiration du verrou via le bloc de code suivant :
jedis.expire(key, timeout);
Parmi eux, key représente le nom du verrou, et timeout représente le délai d'expiration du verrou, en secondes.
Afin d'éviter de supprimer accidentellement les verrous d'autres clients, vous devez déterminer si la valeur du verrou est cohérente avec la valeur que vous avez définie lorsque vous l'avez acquis.
String value = jedis.get(key); if (StringUtils.isNotBlank(value) && value.equals(uuid)) { jedis.del(key); }
Parmi eux, uuid représente l'identifiant unique du client pour obtenir le verrou.
(4) Empêcher la suppression accidentelle des verrous d'autres clients
Après avoir utilisé le verrou, nous devons libérer le verrou correctement, sinon les verrous d'autres clients seront accidentellement supprimés.
Par conséquent, afin d'éviter que les verrous d'autres clients ne soient accidentellement supprimés, nous devons ajouter un identifiant unique au code.
Tout d'abord, lors du processus d'acquisition du verrou, nous devons générer un identifiant unique pour le client, comme indiqué ci-dessous :
String uuid = UUID.randomUUID().toString();
Ensuite, lors du processus d'acquisition et de libération du verrou, nous devons déterminer si le la valeur correspondant à la clé est la même que l'uuid Equal pour déterminer si le verrou est acquis par le client actuel, et dans le processus d'acquisition et de libération du verrou, l'uuid doit être défini comme valeur sur la valeur correspondant à la clé .
Le code spécifique est le suivant :
boolean lock = jedis.setnx(key, uuid) == 1; if (lock) { jedis.expire(key, timeout); } // 释放锁 String value = jedis.get(key); if (StringUtils.isNotBlank(value) && value.equals(uuid)) { jedis.del(key); }
(5) Exemples d'utilisation incorrects
Dans le processus d'utilisation des verrous distribués, si nous rencontrons les situations suivantes, un blocage se produira :
// 获取锁 jedis.setnx(key, value); // 不释放锁
Par conséquent, lors de l'utilisation Pendant le verrouillage processus, vous devez faire attention à déverrouiller correctement le verrou, sinon cela entraînera des conséquences imprévisibles sur le système.
(6) Classe d'implémentation
Enfin, voyons comment encapsuler le code ci-dessus dans une classe de verrouillage distribué Redis.
import redis.clients.jedis.Jedis; import java.util.UUID; public class RedisLock { private static final String LOCK_SUCCESS = "OK"; private static final String SET_IF_NOT_EXIST = "NX"; private static final String SET_WITH_EXPIRE_TIME = "PX"; private Jedis jedis; public RedisLock(Jedis jedis) { this.jedis = jedis; } /** * 尝试获取分布式锁 * @param key 锁 * @param requestId 请求标识 * @param expireTime 超期时间(秒) * @return 是否获取成功 */ public boolean tryGetDistributedLock(String key, String requestId, int expireTime) { String result = jedis.set(key, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime); return LOCK_SUCCESS.equals(result); } /** * 释放分布式锁 * @param key 锁 * @param requestId 请求标识 * @return 是否释放成功 */ public boolean releaseDistributedLock(String key, String requestId) { String value = jedis.get(key); if (value != null && value.equals(requestId)) { jedis.del(key); return true; } return false; } /** * 获取请求标识 * @return 请求标识 */ public static String getRequestId() { return UUID.randomUUID().toString(); } }
À ce stade, nous avons terminé la mise en œuvre du verrouillage distribué Redis.
4. Résumé
Cet article aide les lecteurs à comprendre comment utiliser Redis pour implémenter des verrous distribués en présentant les scénarios d'application, les principes et les méthodes de mise en œuvre des verrous distribués Redis. Étant donné que la mise en œuvre de verrous distribués est relativement complexe, nous devons prêter attention à certains détails, tels que déterminer si la valeur du verrou est cohérente avec la valeur définie lors de son acquisition et définir uuid comme valeur de la clé pendant le processus de acquérir et libérer le verrou. La valeur correspondante est moyenne. Ce n'est qu'en utilisant correctement les verrous distribués que la cohérence et la fiabilité des données dans un système distribué peuvent être garanties.
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!