基于Redis分布式锁

本文详细介绍了基于Redis的分布式锁的设计要求,包括互斥性、无死锁、独立性和容错性。讨论了单节点下Redis分布式锁的问题及解决方案,如加入超时时间、使用签名验证以及利用Lua脚本来保证原子性。同时,提出了锁的重入性和RedLock算法以提高系统的稳定性,以及在不同分布式环境下的实现方式,如主从、集群和哨兵模式。文章还提到了其他分布式锁实现,如MySQL、ZK和自研的Chubby锁。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 基本概况

    1. 分布式锁的要求:
      1. 互斥性。在任意时刻,只有一个客户端能持有锁。
      2. 不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
      3. 独立性。加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。
      4. 具有容错性。只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。
    2. 互斥性
      1. SET key value [EX seconds] [PX milliseconds] [NX|XX] releaseLockTime
        1. NX – 不存在时才能设置成功. XX – 存在时才能设置成功
        2. EX = seconds; PX = milliseconds
        3. 单语句保证了原子性操作,即加锁判断和设置过期时间在一个原子操作中完成.
      2. DEL key
  2. 单节点下的redis分布式锁

    1. 持锁节点宕机(死锁)

      在这里插入图片描述

      解决方案: 加入超时时间releaseLockTime

    2. 持锁线程的任务执行时间大于超时时间(独立性)

      在这里插入图片描述

      解决方案:

      利用value给锁加上"签名",在删除锁时,需要验证签名.签名不对不允许删除.

    3. 持锁线程通过验证时,超时锁自动释放(原子性问题)

      在这里插入图片描述

      解决方案: Lua脚本(redis的eval命令执行Lua代码的时候,Lua代码将被当成一个命令去执行,并且直到eval命令执行完成,Redis才会执行其他命令。)

    4. 思考:保证任务执行时间小于锁的释放时间

    5. 进一步: 锁的重入性

      解决方案:利用value值进行校验,通过校验则允许持有锁(保证原子性),同时维护一个计数器,记录持锁深度,当深度为0时才能进行解锁操作.

  3. 防止redis挂掉(稳定性

    1. RedLock:利用多独立节点进行容灾。
    2. 算法逻辑(redlock)
      1. 记录开始时间
      2. 依次向每个节点尝试获取锁(set失败后,检查value有效性,原子操作),超时默认失败
      3. 当请求到超过半数的成功后,计算当前时间是否已经到达锁释放时间(防止时钟漂移)
      4. 若未到达释放时间,则表示获得锁
      5. 获取锁失败或者结束时向所有节点释放锁
      6. 注意,节点宕机后,再次重启时间应该大于释放时间(防止其他线程协调失败节点和宕机节点获取到锁)
      7. 注意,竞争失败后应该稍等一段时间,避免冲突,导致谁都拿不到过半的锁。
    3. 注意的问题
      1. 释放时间和业务时间的判断
  4. 分布式环境

    1. 主从——客户端分片
    2. 集群——服务器端分片
    3. 哨兵——代理端分片
  5. 其他分布式锁的实现方式

    1. MySQL
    2. ZK
    3. Redis
    4. 自研分布式锁:如谷歌的 Chubby。

参考:

http://cmsblogs.com/?p=3268

https://redis.io/topics/distlock

http://redisdoc.com/string/index.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值