Maison >développement back-end >tutoriel php >Utiliser Redis en PHP pour implémenter la commutation intelligente des verrous distribués

Utiliser Redis en PHP pour implémenter la commutation intelligente des verrous distribués

王林
王林original
2023-05-22 08:36:05903parcourir

Dans un système distribué, étant donné que plusieurs nœuds fonctionnent sur la même ressource en même temps, des conflits de concurrence sont susceptibles de se produire. Pour résoudre ce problème, nous utilisons généralement des verrous distribués pour contrôler l'accès aux ressources partagées. Redis est un cache distribué efficace qui peut être utilisé pour implémenter des verrous distribués. Cet article explique comment utiliser Redis en PHP pour implémenter des verrous distribués et réaliser une commutation intelligente.

1. Qu'est-ce qu'un verrou distribué ?

Le verrouillage distribué signifie que lorsque plusieurs nœuds accèdent à des ressources partagées, un seul nœud peut exploiter la ressource et les autres nœuds doivent attendre. Les verrous distribués contiennent deux opérations : l'acquisition de verrous et la libération des verrous. L'opération d'acquisition du verrou doit garantir la sécurité des threads et éviter l'acquisition répétée du verrou ; l'opération de libération du verrou doit garantir que le verrou est correctement libéré pour éviter un blocage.

2. Utilisez Redis pour implémenter des verrous distribués

Redis est une base de données en mémoire qui peut accéder rapidement aux données et prend en charge la distribution. Dans Redis, vous pouvez utiliser la commande set pour définir la clé et la valeur. Si la clé n'existe pas, le paramètre peut réussir ; si la clé existe déjà, le paramètre échouera. Cette fonctionnalité peut être utilisée pour implémenter des verrous distribués.

La mise en œuvre spécifique peut être divisée en deux étapes. La première étape consiste à acquérir le verrou. Utilisez la commande set pour définir une clé. Si le réglage est réussi, cela signifie que le verrou a été acquis avec succès. Sinon, cela signifie que le verrou a été acquis par d'autres nœuds. La deuxième étape consiste à libérer le verrou et à utiliser la commande del pour supprimer la clé.

Ce qui suit est un exemple de code PHP qui utilise Redis pour implémenter des verrous distribués :

class RedisLock{
    protected $redis;
    protected $lockKey = 'distributed_lock';
    protected $timeout = 30; // 默认锁超时时间30s

    function __construct(){
        $this->redis = new Redis();
        $this->redis->connect('127.0.0.1', 6379);
    }

    function getRedisClient(){
        return $this->redis;
    }

    function setLock($key = ''){
        if(empty($key)){
            $key = $this->lockKey;
        }else{
            $key = $this->lockKey . '_' . $key; // 如果有传入锁键名,则拼接上前缀方便管理
        }

        $timeout = $this->timeout;

        while ($timeout > 0) { // 如果锁未超时,则等待获取锁
            $result = $this->redis->set($key, time() + $timeout, ['nx', 'ex' => $timeout]);

            if ($result){
                return true;
            }

            sleep(1); // 每次等待1秒钟
            $timeout = $timeout -1;
        }

        return false;
    }

    function unlock($key = ''){
        if(empty($key)){
            $key = $this->lockKey;
        }else{
            $key = $this->lockKey . '_' . $key; // 如果有传入锁键名,则拼接上前缀方便管理
        }

        return $this->redis->del($key);
    }
}

Utilisez cette classe pour obtenir facilement le verrou :

$lock = new RedisLock();
if($lock->setLock()){
    // 执行需要获得锁的操作
    $lock->unlock();
}

3. Implémentez une commutation de verrouillage intelligente

L'implémentation du verrou distribué ci-dessus est relativement simple, mais quand Lorsqu'un nœud tombe en panne, cela provoque des problèmes. Par exemple, le timing : le nœud A acquiert le verrou, mais trouve un défaut pendant le fonctionnement, ce qui empêche le verrou d'être libéré normalement. À ce moment-là, le nœud B tente d'acquérir le verrou, mais échoue car le nœud A détient toujours le verrou. . Afin de résoudre ce problème, nous pouvons mettre en œuvre une commutation de verrouillage intelligente.

Tout d'abord, nous devons implémenter un mécanisme de réinitialisation du délai d'expiration du verrouillage, c'est-à-dire qu'une fois le délai d'expiration du verrouillage écoulé, le verrou est réinitialisé à un état disponible. Ceci peut être réalisé grâce à une tâche planifiée. Deuxièmement, nous devons enregistrer le détenteur du verrou. Lorsqu'une situation anormale se produit, le verrou du détenteur peut être libéré manuellement. Enfin, nous devons mettre en œuvre un mécanisme de commutation de verrouillage, c'est-à-dire que lorsque le nœud détenant le verrou tombe en panne, d'autres nœuds peuvent automatiquement basculer vers le détenteur du verrou.

Pour une implémentation spécifique, veuillez vous référer à l'exemple de code ci-dessous :

class RedisLock {
    protected $redis;
    protected $lockKey = 'distributed_lock';
    protected $timeout = 30; // 默认锁超时时间30s

    // 锁的持有者
    protected $holder;

    // 获取锁的时间戳,用于超时释放锁
    protected $lockTime;

    function __construct(){
        $this->redis = new Redis();
        $this->redis->connect('127.0.0.1', 6379);
    }

    function getRedisClient(){
        return $this->redis;
    }

    function setLock($key = ''){
        if(empty($key)){
            $key = $this->lockKey;
        }else{
            $key = $this->lockKey . '_' . $key; // 如果有传入锁键名,则拼接上前缀方便管理
        }

        $timeout = $this->timeout;

        // 检查锁是否已被其他节点持有
        if($lockTime = $this->redis->get($key)){
            // 计算锁的剩余时间
            $remainTime = $lockTime + $timeout - time();

            // 如果锁剩余时间大于0,则表示其他节点持有锁
            if($remainTime > 0){
                return false;
            }
        }

        // 尝试获取锁
        $result = $this->redis->set($key, time() + $timeout, ['nx', 'ex' => $timeout]);

        if ($result){
            $this->holder = $key;
            $this->lockTime = time() + $timeout;

            return true;
        }

        return false;
    }

    function unlock($key = ''){
        if(empty($key)){
            $key = $this->lockKey;
        }else{
            $key = $this->lockKey . '_' . $key; // 如果有传入锁键名,则拼接上前缀方便管理
        }

        if($this->holder != $key){
            return false;
        }

        return $this->redis->del($key);
    }

    // 定时任务,每隔一段时间检查锁的持有者是否存活,如果不存活,则尝试切换为当前节点
    function timeoutReset(){
        while(true){
            if(time() > $this->lockTime){
                $this->redis->set($this->holder, '', ['nx', 'ex' => 1]);
            }

            $this->holder = $this->redis->get($this->lockKey);

            if(!$this->holder){
                $this->setLock();
            }

            sleep(1); // 每个一秒执行一次
        }
    }
}

Ce qui précède implémente la commutation de verrouillage intelligente. Si le nœud A échoue, les autres nœuds basculeront automatiquement vers le détenteur du verrou une fois le délai écoulé. Ce mécanisme garantit la haute disponibilité et la fiabilité des verrous distribués.

4. Résumé

Cet article explique comment utiliser Redis pour implémenter des verrous distribués et implémenter un mécanisme de commutation de verrouillage intelligent. Cette solution garantit la haute disponibilité et la fiabilité des serrures distribuées et peut être largement utilisée dans les systèmes distribués. Dans le même temps, cette solution peut également être utilisée pour résoudre d'autres problèmes nécessitant des mécanismes de verrouillage, tels que les verrous en lecture-écriture de bases de données, les transactions distribuées, etc.

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:
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