暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Redis分布式锁

董源龙 2021-09-30
167

使用lua脚本

加锁命令

    set

        SET lockKey value NX PX expireTime

    eg:

        jedis.set(keys,uuid,"NX","PX",30000)

    incr

        原子操作

    3、setNX

        不能设置过期时间,需借助事物设置过期时间

        

  




设计分布锁

  1. 同一线程可重入。

  2. 加锁要保证原子性,使用setnx。

  3. value要具有唯一性。

  4. 释放锁需要首先释放锁的线程与加锁的线程是不是同一个。

  5. 释放锁时要验证value值。


释放锁时为何要验证value值

    如果A线程执行业务耗时超过了锁的持有时间,锁会自动释放;锁自动释放之后,线程B又加锁成功,此时A线程执行完业务逻辑之后,去释放锁,但A线程的锁已经自动释放了,如果没有value来标识的话,它可能就会去释放B线程的锁

锁超时问题

    A线程执行业务耗时超过了锁的持有时间,锁会自动释放


Redis集群发生主从切换,出现锁丢失问题

    如果master节点由于某原因发生了主从切换,那么就会出现锁丢失的情况;在master节点上拿到了锁,但是这个加锁的key还没有同步到slave节点,master故障,发生故障转移,slave节点升级为master节点,导致锁丢失。解决方案:Redlock



RedLock

    RedLock算法虽然是需要多个实例,但是这些实例都是独自部署的,没有主从关系。之所以要用独立的,是避免了Redis异步复制造成的锁丢失。在Java中Redisson包实现了对RedLock的封装。

RedLock 的加锁过程

    N个Redis服务或集群

  1. Client 获取当前毫秒级时间戳,并设置超时时间 TTL

  2. 依次向 N 个 Redis 服务发出请求,用能够保证全局唯一的 value 申请锁 key

  3. 如果从N/2+1个Redis 服务中都获取锁成功,那么,本次分布式锁的获取被视为成功,否则视为获取锁失败

  4. 如果获取锁失败,或执行达到 TTL,则向所有 Redis 服务都发出解锁请求。


Redisson中关于分布锁的实现

    缺点

    加锁时只作用在一个Redis节点上

        它加锁时只作用在一个Redis节点上,即使Redis通过Sentinel保证高可用,如果这个master节点由于某些原因发生了主从切换,那么就会出现锁丢失的情况。

    RedissonRedLock才是最终的银弹,只是使用时需要同时在多个节点上加锁,效率略低 

    Redisson使用守护线程来进行锁的续期,(当主线程销毁时,守护线程和主线程一起销毁。)防止程序宕机后,线程依旧不断续命,造成死锁!

    另外,Redisson还实现并且优化了RedLock算法、公平锁、可重入锁、连锁等操作,使Redis分布式锁的实现方式更加简便高效!

看门狗机制-Watchdog

    

    定义:

        RedLock的Java版本Redisson实现了一种保证锁失效时间绝对大于业务程序执行时间的机制。

    主要原理

        在程序成功获取锁之后,会fork一条子线程去不断的给该锁续期,直至该锁释放为止。




和zookeeper比较

    貌似redis比较复杂,需要考虑过期时间、原子性、高可用等

    如果Redis获取锁的那个客户端挂了,那么只能等待超时时间之后才能释放锁

    而对于ZooKeeper,因为创建的是临时znode,只要客户端挂了,znode就没了,此时就自动释放锁

ZK CP,选举导致不可用

Redis AP


文章转载自董源龙,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论