Cet article vous apporte une explication détaillée (exemple de code) de l'utilisation de Redis pour implémenter des verrous distribués. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.
Raisons du choix de Redis pour implémenter des verrous distribués
Redis a des performances élevées
La commande Redis prend mieux en charge cela et est plus pratique à implémenter
Introduction à l'utilisation des commandes
SETNX
SETNX key valexpire
expire key timeoutdelete
delete keyLors de l'utilisation de Redis pour implémenter des verrous distribués, ces trois commandes sont principalement utilisées.
implémente
en utilisant jedis pour se connecter à Redis.
Idée d'implémentation
Lors de l'acquisition du verrou, utilisez setnx pour le verrouiller et utilisez la commande expire pour ajouter un délai d'attente au verrou. Après ce délai, le le verrou sera automatiquement libéré. La valeur est un UUID généré aléatoirement, qui est utilisé pour juger du moment où le verrou est libéré.
Lors de l'acquisition du verrou, un délai d'attente est également défini pour l'acquisition. Si ce délai est dépassé, l'acquisition du verrou sera abandonnée.
Lors de la libération d'un verrou, utilisez l'UUID pour déterminer s'il s'agit du verrou. S'il s'agit du verrou, exécutez delete pour libérer le verrou.
Le code de base du verrou distribué est le suivant :
import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.Transaction; import redis.clients.jedis.exceptions.JedisException; import java.util.List; import java.util.UUID; public class DistributedLock { private final JedisPool jedisPool; public DistributedLock(JedisPool jedisPool) { this.jedisPool = jedisPool; } /** * 加锁 * @param locaName 锁的key * @param acquireTimeout 获取超时时间 * @param timeout 锁的超时时间 * @return 锁标识 */ public String lockWithTimeout(String locaName, long acquireTimeout, long timeout) { Jedis conn = null; String retIdentifier = null; try { // 获取连接 conn = jedisPool.getResource(); // 随机生成一个value String identifier = UUID.randomUUID().toString(); // 锁名,即key值 String lockKey = "lock:" + locaName; // 超时时间,上锁后超过此时间则自动释放锁 int lockExpire = (int)(timeout / 1000); // 获取锁的超时时间,超过这个时间则放弃获取锁 long end = System.currentTimeMillis() + acquireTimeout; while (System.currentTimeMillis() results = transaction.exec(); if (results == null) { continue; } retFlag = true; } conn.unwatch(); break; } } catch (JedisException e) { e.printStackTrace(); } finally { if (conn != null) { conn.close(); } } return retFlag; } }
Test
Ce qui suit est un exemple simple pour tester le verrou distribué qui vient d'être implémenté.
Dans l'exemple, 50 threads sont utilisés pour simuler une vente flash d'un produit, et l'opérateur -- est utilisé pour réduire le produit. L'ordre des résultats permet de voir s'il est dans un état verrouillé. .
Simulez le service de vente flash, configurez-y le pool de threads Jedis et transmettez-le au verrou distribué lors de l'initialisation pour son utilisation.
import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; public class Service { private static JedisPool pool = null; static { JedisPoolConfig config = new JedisPoolConfig(); // 设置最大连接数 config.setMaxTotal(200); // 设置最大空闲数 config.setMaxIdle(8); // 设置最大等待时间 config.setMaxWaitMillis(1000 * 100); // 在borrow一个jedis实例时,是否需要验证,若为true,则所有jedis实例均是可用的 config.setTestOnBorrow(true); pool = new JedisPool(config, "127.0.0.1", 6379, 3000); } DistributedLock lock = new DistributedLock(pool); int n = 500; public void seckill() { // 返回锁的value值,供释放锁时候进行判断 String indentifier = lock.lockWithTimeout("resource", 5000, 1000); System.out.println(Thread.currentThread().getName() + "获得了锁"); System.out.println(--n); lock.releaseLock("resource", indentifier); } }
Simuler le fil pour effectuer un service de vente flash
public class ThreadA extends Thread { private Service service; public ThreadA(Service service) { this.service = service; } @Override public void run() { service.seckill(); } } public class Test { public static void main(String[] args) { Service service = new Service(); for (int i = 0; i <p>Les résultats sont les suivants, et les résultats sont dans l'ordre. </p><p style="text-align: center;"><span class="img-wrap"><img src="https://img.php.cn//upload/image/211/984/157/1540025904941327.png" title="1540025904941327.png" alt="Explication détaillée de lutilisation de Redis pour implémenter des verrous distribués (exemple de code)"></span></p><p>Si vous commentez la partie qui utilise des verrous </p><pre class="brush:php;toolbar:false">public void seckill() { // 返回锁的value值,供释放锁时候进行判断 //String indentifier = lock.lockWithTimeout("resource", 5000, 1000); System.out.println(Thread.currentThread().getName() + "获得了锁"); System.out.println(--n); //lock.releaseLock("resource", indentifier); }
Comme le montrent les résultats, certains sont exécutés de manière asynchrone.
Dans un environnement distribué, il est parfois important de verrouiller les ressources, par exemple en récupérant une certaine ressource. Dans ce cas, vous pouvez utiliser des verrous distribués. assurer un bon contrôle des ressources.
Bien sûr, dans une utilisation spécifique, de nombreux facteurs doivent être pris en compte, tels que la sélection du délai d'attente et la sélection du temps d'acquisition du verrou, qui ont un grand impact sur le degré de concurrence du verrou distribué implémenté. ci-dessus n'est qu'une implémentation simple est principalement une idée.
[En fait, la fiabilité de l'utilisation de zookeeper est supérieure à celle du verrouillage distribué implémenté par Redis, mais en comparaison, les performances de Redis sont meilleures. ]
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!