Maison Problème commun Quelles sont les trois méthodes de mise en œuvre des verrous distribués ?

Quelles sont les trois méthodes de mise en œuvre des verrous distribués ?

Dec 14, 2020 am 11:29 AM
分布式锁

Trois façons d'implémenter des verrous distribués : 1. Implémenter des verrous distribués basés sur la base de données ; 2. Implémenter des verrous distribués basés sur le cache (Redis, etc.) ; Du point de vue des performances (de haut en bas) : "Mode cache > Mode Zookeeper > = Mode base de données".

Quelles sont les trois méthodes de mise en œuvre des verrous distribués ?

L'environnement d'exploitation de cet article : système Windows, redis 6.0, ordinateur thinkpad t480.

Trois façons d'implémenter des verrous distribués :

1. Implémenter des verrous distribués basés sur une base de données
2. ) ;
3. Implémenter des verrous distribués basés sur Zookeeper ;

1. Implémenter des verrous distribués basés sur une base de données

1.

Utilisez select …where… pour le verrouillage exclusif de mise à jour

Remarque : les autres fonctions supplémentaires sont fondamentalement les mêmes que celles de l'implémentation. Ce qu'il faut noter ici, c'est "where name=lock", le nom. Le champ doit être indexé, sinon la table sera verrouillée. Dans certains cas, par exemple si la table n'est pas grande, l'optimiseur MySQL n'utilisera pas cet index, provoquant des problèmes de verrouillage de table.

2. Verrouillage optimiste

La plus grande différence entre le verrouillage dit optimiste et les précédents est qu'il est basé sur l'idée CAS. Il ne s'exclut pas mutuellement et ne provoquera pas de verrouillage. en attente et consommer des ressources. Il est considéré comme n'existant pas pendant l'opération. Les conflits de concurrence ne peuvent être détectés qu'après l'échec de la version de mise à jour. Nos ventes urgentes et nos ventes flash utilisent cette mise en œuvre pour éviter la survente.
Implémentez le verrouillage optimiste en ajoutant un champ de numéro de version incrémentiel

Deuxièmement, implémentez le verrouillage distribué basé sur le cache (Redis, etc.)

1. Introduction à l'utilisation des commandes :
(1) SETNX
SETNX key val : Si et seulement si la clé n'existe pas, définissez une chaîne avec key val et renvoyez 1. ; if Si la clé existe, ne faites rien et renvoyez 0.
(2) expire
expiration du délai d'expiration de la clé : définissez un délai d'expiration pour la clé, l'unité est la deuxième. Le verrou sera automatiquement libéré après ce délai pour éviter un blocage.
(3) delete
delete key : delete key

Lors de l'utilisation de Redis pour implémenter des verrous distribués, ces trois commandes sont principalement utilisées.

2. Idée d'implémentation :
(1) 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 verrou sera activé. automatiquement libéré. ​​La valeur du verrou Il s'agit d'un UUID généré aléatoirement, qui est utilisé pour juger du moment où le verrou est libéré.
(2) 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.
(3) 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.

3. Code d'implémentation simple du verrou distribué :

 /**
    * 分布式锁的简单实现代码    */
   public class DistributedLock {
   
       private final JedisPool jedisPool;
   
       public DistributedLock(JedisPool jedisPool) {
          this.jedisPool = jedisPool;
      }
  
      /**
       * 加锁
       * @param lockName       锁的key
       * @param acquireTimeout 获取超时时间
       * @param timeout        锁的超时时间
       * @return 锁标识
       */
      public String lockWithTimeout(String lockName, long acquireTimeout, long timeout) {
          Jedis conn = null;
          String retIdentifier = null;
          try {
              // 获取连接
              conn = jedisPool.getResource();
              // 随机生成一个value
              String identifier = UUID.randomUUID().toString();
              // 锁名,即key值
              String lockKey = "lock:" + lockName;
              // 超时时间,上锁后超过此时间则自动释放锁
              int lockExpire = (int) (timeout / );
  
              // 获取锁的超时时间,超过这个时间则放弃获取锁
              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;
     }
 }
Copier après la connexion

4. Testez le verrou distribué qui vient d'être implémenté

Dans l'exemple, 50 threads sont utilisés pour simuler une vente flash de un produit, utilisez -operator pour obtenir une réduction du produit. D'après l'ordre des résultats, on peut 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.

public class Service {

    private static JedisPool pool = null;

    private DistributedLock lock = new DistributedLock(pool);

    int n = 500;

    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);
    }

    public void seckill() {
        // 返回锁的value值,供释放锁时候进行判断
        String identifier = lock.lockWithTimeout("resource", 5000, 1000);
        System.out.println(Thread.currentThread().getName() + "获得了锁");
        System.out.println(--n);
        lock.releaseLock("resource", identifier);
    }
}
Copier après la connexion

Simuler des threads pour effectuer des services flash kill

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, les résultats sont dans l'ordre : </p><p><img src="/static/imghw/default1.png" data-src="https://img.php.cn/upload/article/000/000/024/0c1cb2ceea4c8cbfa184228a02822f99-1.png" class="lazy" alt="Quelles sont les trois méthodes de mise en œuvre des verrous distribués ?"></p><p>Si vous commentez l'utilisation des verrous Partie : </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);
}
Copier après la connexion

Comme le montrent les résultats, certains sont exécutés de manière asynchrone :

Quelles sont les trois méthodes de mise en œuvre des verrous distribués ?

Troisièmement, distribué basé sur Zookeeper Lock

ZooKeeper est un composant open source qui fournit des services de cohérence pour les applications distribuées. En interne, il s'agit d'une arborescence de répertoires de système de fichiers hiérarchique, qui stipule qu'il peut y en avoir. n'en être qu'un dans le même répertoire. Nom de fichier unique. Les étapes pour implémenter des verrous distribués basés sur ZooKeeper sont les suivantes :

(1) Créer un répertoire mylock
(2) Le thread A crée un nœud de séquence temporaire dans le répertoire mylock s'il souhaite acquérir le lock;
(3 ) Récupère tous les nœuds enfants du répertoire mylock, puis récupère les nœuds frères plus petits que lui-même. S'il n'existe pas, cela signifie que le thread actuel a le plus petit numéro de séquence et obtient le verrou ;
(4) Le thread B récupère tous les nœuds et détermine qu'il ne s'agit pas du plus petit nœud, configuré pour surveiller le nœud plus petit que lui
(5) Une fois le traitement terminé, supprimez son propre nœud, le thread B ; écoute l'événement de changement, détermine s'il s'agit du plus petit nœud et, si tel est le cas, obtient le verrou.

Ici est recommandé une bibliothèque open source Apache Curator, qui est un client ZooKeeper. L'InterProcessMutex fourni par Curator est l'implémentation de verrous distribués. La méthode d'acquisition est utilisée pour acquérir des verrous et la méthode de libération est utilisée pour. libérer les verrous.

Le code source d'implémentation est le suivant :

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.RetryNTimes;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

/**
 * 分布式锁Zookeeper实现
 *
 */
@Slf4j
@Component
public class ZkLock implements DistributionLock {
private String zkAddress = "zk_adress";
    private static final String root = "package root";
    private CuratorFramework zkClient;

    private final String LOCK_PREFIX = "/lock_";

    @Bean
    public DistributionLock initZkLock() {
        if (StringUtils.isBlank(root)) {
            throw new RuntimeException("zookeeper 'root' can't be null");
        }
        zkClient = CuratorFrameworkFactory
                .builder()
                .connectString(zkAddress)
                .retryPolicy(new RetryNTimes(2000, 20000))
                .namespace(root)
                .build();
        zkClient.start();
        return this;
    }

    public boolean tryLock(String lockName) {
        lockName = LOCK_PREFIX+lockName;
        boolean locked = true;
        try {
            Stat stat = zkClient.checkExists().forPath(lockName);
            if (stat == null) {
                log.info("tryLock:{}", lockName);
                stat = zkClient.checkExists().forPath(lockName);
                if (stat == null) {
                    zkClient
                            .create()
                            .creatingParentsIfNeeded()
                            .withMode(CreateMode.EPHEMERAL)
                            .forPath(lockName, "1".getBytes());
                } else {
                    log.warn("double-check stat.version:{}", stat.getAversion());
                    locked = false;
                }
            } else {
                log.warn("check stat.version:{}", stat.getAversion());
                locked = false;
            }
        } catch (Exception e) {
            locked = false;
        }
        return locked;
    }

    public boolean tryLock(String key, long timeout) {
        return false;
    }

    public void release(String lockName) {
        lockName = LOCK_PREFIX+lockName;
        try {
            zkClient
                    .delete()
                    .guaranteed()
                    .deletingChildrenIfNeeded()
                    .forPath(lockName);
            log.info("release:{}", lockName);
        } catch (Exception e) {
            log.error("删除", e);
        }
    }

    public void setZkAddress(String zkAddress) {
        this.zkAddress = zkAddress;
    }
}
Copier après la connexion

Avantages : Il dispose de fonctionnalités de haute disponibilité, de réentrée et de verrouillage de blocage, qui peuvent résoudre le problème de blocage en cas d'échec.

Inconvénients : comme les nœuds doivent être créés et supprimés fréquemment, les performances ne sont pas aussi bonnes que celles de Redis.

Quatre comparaison

Implémentation du verrouillage distribué de la base de données
Inconvénients :

1. Les performances de l'opération de base de données sont médiocres et il existe un risque de verrouillage de la table
2. Après l'échec de l'opération non bloquante, une interrogation est requise et les ressources CPU sont occupées
3. Aucun commit pour un ; ou une interrogation pendant une longue période, peut occuper plus de ressources de connexion

Implémentation du verrouillage distribué Redis (cache)
Inconvénients :

1. l'échec de la suppression du verrou est difficile à contrôler
2 Non bloquant, après l'échec de l'opération, une interrogation est requise et les ressources CPU sont occupées ;

Implémentation du verrouillage distribué ZK
Inconvénients : Les performances ne sont pas aussi bonnes que l'implémentation de Redis, la raison principale est que les opérations d'écriture (acquisition et libération des verrous) doivent être effectuées sur le leader puis synchronisées avec les suiveurs.

En bref : ZooKeeper a de bonnes performances et une bonne fiabilité.

Du point de vue de la facilité de compréhension (de faible à élevée) Base de données> Cache> 🎜>

Du point de vue des performances (de haut en bas) Cache > Zookeeper > Base de données

Recommandations associées : "

Enseignement de la programmation

"

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 de ce site Web
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

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

Video Face Swap

Video Face Swap

Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Serrure distribuée : 5 cases, de l'entrée à l'enterrement Serrure distribuée : 5 cases, de l'entrée à l'enterrement Aug 24, 2023 pm 02:48 PM

Ce que je veux partager avec vous aujourd'hui, ce sont les verrous distribués. Cet article utilise cinq cas, diagrammes, analyses de code source, etc. Les verrous courants tels que synchronisé et Lock sont tous implémentés sur la base d'une seule JVM. Que devons-nous faire dans un scénario distribué ? A cette époque, des verrous distribués sont apparus.

Utilisation de ZooKeeper pour le traitement des verrous distribués dans le développement d'API Java Utilisation de ZooKeeper pour le traitement des verrous distribués dans le développement d'API Java Jun 17, 2023 pm 10:36 PM

À mesure que les applications modernes continuent d’évoluer et que le besoin de haute disponibilité et de simultanéité augmente, les architectures de systèmes distribués deviennent de plus en plus courantes. Dans un système distribué, plusieurs processus ou nœuds s'exécutent en même temps et accomplissent des tâches ensemble, et la synchronisation entre les processus devient particulièrement importante. Étant donné que de nombreux nœuds d'un environnement distribué peuvent accéder simultanément à des ressources partagées, la manière de gérer les problèmes de concurrence et de synchronisation est devenue une tâche importante dans un système distribué. À cet égard, ZooKeeper est devenu une solution très populaire. ZooKee

Comparaison d'Etcd dans l'implémentation Redis des verrous distribués Comparaison d'Etcd dans l'implémentation Redis des verrous distribués Jun 20, 2023 pm 05:51 PM

Avec la popularisation progressive des systèmes distribués, les verrous distribués sont devenus un moyen important pour garantir la stabilité du système et la cohérence des données. En tant que base de données à mémoire distribuée hautes performances, Redis est naturellement devenue l'une des implémentations importantes de verrous distribués. Cependant, ces dernières années, Etcd a reçu de plus en plus d’attention en tant que solution émergente de cohérence distribuée. Cet article discutera des similitudes et des différences entre l'implémentation des verrous distribués par Redis et Etcd sous des aspects tels que les principes d'implémentation et l'analyse comparative. Le principe de mise en œuvre des verrous distribués Redis La mise en œuvre des verrous distribués Redis

La solution reine parmi les serrures distribuées - Redisson La solution reine parmi les serrures distribuées - Redisson Aug 24, 2023 pm 03:31 PM

Si vous avez déjà utilisé Redis, vous obtiendrez deux fois le résultat avec la moitié de l'effort en utilisant Redisson, qui constitue le moyen le plus simple et le plus pratique d'utiliser Redis. Le but de Redisson est de promouvoir la séparation des préoccupations des utilisateurs (Separation of Concern) de Redis, afin que les utilisateurs puissent se concentrer davantage sur le traitement de la logique métier.

Utiliser Redis pour implémenter des verrous distribués en PHP Utiliser Redis pour implémenter des verrous distribués en PHP May 15, 2023 pm 03:51 PM

Avec le développement rapide d’Internet et la forte augmentation des visites de sites Web, l’importance des systèmes distribués est progressivement devenue importante. Dans les systèmes distribués, les problèmes de synchronisation simultanée et de cohérence des données sont inévitablement impliqués. Les verrous distribués, comme moyen de résoudre les problèmes de synchronisation simultanée, ont progressivement été largement utilisés dans les systèmes distribués. En PHP, vous pouvez utiliser Redis pour implémenter des verrous distribués, que cet article présentera. Qu'est-ce qu'un verrou distribué ? Dans un système distribué, lorsque plusieurs machines traitent la même tâche ensemble, afin d'éviter l'apparition de plusieurs machines

Comment utiliser les verrous distribués pour contrôler les accès simultanés dans MySQL ? Comment utiliser les verrous distribués pour contrôler les accès simultanés dans MySQL ? Jul 30, 2023 pm 10:04 PM

Comment utiliser les verrous distribués pour contrôler les accès simultanés dans MySQL ? Dans les systèmes de bases de données, un accès simultané élevé est un problème courant et les verrous distribués sont l'une des solutions courantes. Cet article explique comment utiliser les verrous distribués dans MySQL pour contrôler les accès simultanés et fournit des exemples de code correspondants. 1. Principe Les verrous distribués peuvent être utilisés pour protéger les ressources partagées afin de garantir qu'un seul thread puisse accéder à la ressource en même temps. Dans MySQL, les verrous distribués peuvent être implémentés de la manière suivante : Créez un fichier nommé lock_tabl

Explication détaillée de l'implémentation du verrouillage distribué dans Redis Explication détaillée de l'implémentation du verrouillage distribué dans Redis Jun 21, 2023 am 11:02 AM

Avec le développement rapide de l'Internet mobile et la croissance explosive du volume de données, les systèmes distribués deviennent de plus en plus populaires. Dans les systèmes distribués, le problème des opérations simultanées est devenu de plus en plus important lorsque plusieurs threads demandent des ressources partagées en même temps, ces ressources doivent être verrouillées pour garantir la cohérence des données. Les verrous distribués sont l'une des solutions efficaces pour implémenter des opérations simultanées dans les systèmes distribués. Cet article présentera en détail comment utiliser Redis pour implémenter des verrous distribués. Redis Basics Redis est un système de stockage clé-valeur basé sur la mémoire et distribué

Comparaison consul de l'implémentation Redis des verrous distribués Comparaison consul de l'implémentation Redis des verrous distribués Jun 20, 2023 pm 02:38 PM

Comparaison de Consul implémentant des verrous distribués dans Redis Dans les systèmes distribués, les verrous sont un mécanisme de synchronisation essentiel. En tant que base de données NoSQL couramment utilisée, la fonction de verrouillage distribué fournie par Redis a reçu une attention et une application généralisées. Cependant, Redis rencontre certains problèmes lors de la mise en œuvre des verrous distribués, tels que la réacquisition des verrous et le traitement des délais d'attente, c'est pourquoi de nouveaux outils ont été développés pour résoudre ces problèmes, notamment Consul. Cet article implémentera les verrous distribués dans Redis et implémentera Consul