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. 持锁节点宕机(死锁)

      基于Redis分布式锁

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

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

      基于Redis分布式锁

      解决方案:

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

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

      基于Redis分布式锁

      解决方案: 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

相关文章:

  • 2021-05-31
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2022-02-02
  • 2021-10-15
  • 2021-08-29
  • 2021-07-09
相关资源
相似解决方案