首页 > 其他 > 详细

《Redis 分布式锁》

时间:2019-08-15 21:10:42      阅读:99      评论:0      收藏:0      [点我收藏+]

一:什么是分布式锁。

  -  通俗来说的话,就是在分布式架构的redis中,使用锁

 

二:分布式锁的使用选择。

  - 当 Redis 的使用场景不多,而且也只是单个在用的时候,可以构建自己使用的 锁。

  - 如果在公司里落地生产环境用分布式锁的时候,一般是会用开源类库。

  - Redis分布式锁,一般就是用 Redisson 框架就好了,非常的简便易用。 

 

三:Redisson 实现Redis分布式锁的原理。

  - 整体流程图

    - 技术分享图片

 

  - 详解

    - 当某个请求的客户端需要加锁时候。

      - 如果该客户端面对的是一个redis cluster集群,他首先会根据hash算法选择一台机器。(一致hash算法)

 

    - 随后会向Redis发送加锁请求(原理为Lua脚本

      - Lua 脚本会保证业务执行的原子性,所以采用 Lua 的方式为加锁命令。

      - 技术分享图片

      - 这个Lua 脚本的大致意思为(这个Key的锁是否存在,如果存在,则一直循环等待,如不存在,则上锁,并设置过期时间。

 

    - watch dog 提供的锁自动延期的能力

      - 加锁的锁key默认生存时间才30秒,如果超过了30秒,客户端1还想一直持有这把锁,怎么办呢?

      - RedisSon 只要加锁成功,就会启动一个watch dog看门狗, 他是一个后台线程,会每隔10秒检查一下 ,如果还持有锁key,那么就会不断的延长锁key的生存时间。

 

四:分布式锁锁带来的问题

  - 在分布式架构中的问题,就是如果你对某个redis master实例,写入了key的锁,此时会异步复制给对应的master slave实例。

  - 但是这个过程中一旦发生redis master宕机,主备切换,redis slave变为了redis master。

  - 接着就会导致,客户端2来尝试加锁的时候,在新的redis master上完成了加锁,而客户端1也以为自己成功加了锁。

  - 此时就会导致多个客户端对一个分布式锁完成了加锁。

  - 这时系统在业务语义上一定会出现问题, 导致各种脏数据的产生 。

  - 这个就是redis cluster/redis master-slave架构的 主从异步复制 导致的redis分布式锁的问题:在redis master实例宕机的时候,可能导致多个客户端同时完成加锁。

 

五:简单实现的redis锁

  - 原理

    -  通过 redis 的 setnx 功能进行加锁

 

  - 实现(PHP)

    • <?php
      /**
       * 创建 Redis 单例
       * @return mixed
       */
      class redisInstance
      {
          static $redis;
      
          private function __construct()
          {
          }
      
          public static function getInstance()
          {
              if (self::$redis) {
                  return self::$redis;
              }
      
              self::$redis = new \Redis();
      
              return self::$redis;
          }
      
      }
      
      class redisLock
      {
          public $reids;
      
          public function __construct()
          {
              $this->reids = redisInstance::getInstance();
          }
      
          /**
           * 键加锁,默认加锁时间为 1分钟 = 60 * 1000(毫秒)
           * @param $key
           * @param int $ttl
           * @return bool
           */
          public function lock($key, $ttl = 60000)
          {
              $lockKey = $key . ‘_lock‘;
      
              // 通过setNx命令拿到锁
              $lock = $this->reids->set($lockKey, 1, [‘NX‘, ‘PX‘ => $ttl]);
      
              // 拿到锁则直接返回
              if ($lock) {
                  return true;
              }
      
              // 没有拿到锁,则一直循环等待锁资源释放
              while (!$lock) {
                   $lock = $this->reids->set($key, 1, [‘NX‘, ‘PX‘ => $ttl]);
              }
      
              return $lock;
          }
      
          /**
           * 释放锁
           * @param $key
           * @return bool
           */
          public function unLock($key)
          {
              $lockKey = $key . ‘_lock‘;
      
              $lock = false;
      
              // 释放锁
              while (!$lock) {
                  $lock = $this->reids->del($lockKey);
              }
      
              return true;
          }
      }
      
      $redis = redisInstance::getInstance();
      $redisLock = new redisLock();
      
      /**
       * 例如,买商品,进行库存递减
       *     1:对库存加锁
       *     2:递减
       *     3:释放锁
       * 影响
       *     加锁导致的并发度降低
       */
      $key = ‘stock‘;
      $redisLock->lock($key);
      $stock = $redis->get($key);
      if ($redis->get($key) <= 0) {
          $redisLock->unLock($key);
          return false;
      }
      $redis->decr($key);
      $redisLock->unLock($key);

       

《Redis 分布式锁》

原文:https://www.cnblogs.com/25-lH/p/11360271.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!