Redis如何实现分布式锁,单机Redis与集群Redis问题解决方案

场景1:在单机场景下,可以通过同步锁进行加锁

  • 在单机系统下,该场景是适用的,所有的线程都需要等待同步锁释放

场景2:分布式场景下的分布式锁

  • 场景1中的代码不适用与分布式系统,因为上述的同步锁是JVM层次的,只能锁住一个分布式中的节点
解决方案

分布式锁适用Redis的setNX【SET if Not eXists】实现,语法如下:

setNX  key  value

  • key:锁的名称
  • value:锁对应的值
  • 如果Redis中没有该锁,上述语句返回1,加锁成功
  • 如果Redis中已有该锁,上述语句返回0,加锁失败
  • 解锁:del  key

场景3:分布式节点加锁成功,释放锁前宕机如何处理

分布式系统中,节点中线程加锁成功后,在处理业务过程中宕机,分布式锁并没有释放,从而导致死锁问题

解决方案
  • 给分布式锁添加过期时间
  • 使用setNX的特殊语法格式,如下:

SET key value EX 10 NX 

  • 设置key的过期时间为10s
  • 解锁:del key

场景4:分布式锁过期释放问题

过期时间释放锁问题的原因:

  1. 过期时间设置的很少
  2. FULL GC执行时间过长
  3. 运维手动调整了过期时间

现存问题:

  1. 分布式中的实例1,加锁成功,在处理业务过程中,锁到期释放,而未执行到释放锁的代码
  2. 实例2在t3时刻,实例1过期释放锁后,获取分布式锁成功
  3. 实例1在t4时刻业务代码处理结束,执行释放锁代码,从而导致实例2的锁被释放
  4. 实例3在实例1释放锁后,重新获取分布式锁
解决方案

1、针对与锁过期问题

  • 启动一个异步线程,定时续期(watchdog 看门狗机制)
  • 获取锁成功后启动异步线程,每隔x秒对当前的锁续期y秒,直到锁被释放停止

2、针对释放其他线程锁的问题

  • 分布式锁的value设置为:唯一的UUID+线程ID
  • 当释放锁时,判断分布式锁的value是否与当前一致,一致则释放
  • 加锁

SET  ${lockName} 唯一的ID值   EX  10  NX

  • 解锁:需要使用rua脚本保证Redis操作的原子性

current_value = get ${lockName}

if ${唯一的ID值} == current_value then 

   DEL ${lockName} 

该方案是单机版Redis的分布式系统中,分布式锁的主流解决方案 


场景5:Redis集群环境中,主节点加锁未同步备节点问题

现存问题:

  1. 在sentinel管理的Redis主备集群中,实例1向主节点加锁成功
  2. 当主节点加锁成功后,未同步至备节点而宕机
  3. sentinel会从备节点中选择一台备节点作为主节点,从而导致锁丢失
  4. 锁丢失从而导致锁失效,其他的实例也可以同时访问共享资源

解决方案
  • 加锁
  1. 向所有节点发出加锁请求
  2. 获取锁成功的数量达到半数以上,才认为加锁成功
  • 解锁:删除所有实例上的锁

场景6:Redis集群环境中,网络通信延迟造成的锁过期问题

现存问题:

  • 实例1向Redis集群中的3个节点发送加锁请求,锁过期为10s
  • 主节点与备节点1s就返回了加锁成功
  • 备2节点由于网络延迟,返回花费了11s,此时主节点与备1节点锁已经删除了

解决方案
  • 加锁
  1. 记录 加锁时的当前时间戳t1
  2. 向所有节点发出加锁请求,为每一个请求设置超时时间(小于锁过期时间ttl),并记录最后收到返回的时间戳t2
  3. 获取锁成功数量达到半数以上,并且t2-t1 < ttl 才认为加锁成功
  • 解锁:删除所有实例上的锁

上述方案就是 Redlock

(Redlock 是一种分布式锁的实现算法,是为了在Redis这类分布式键值存储系统中提供一种互斥机制而设计的。它由Redis的创建者Antirez(Salvatore Sanfilippo)提出,用于在分布式系统中安全地执行互斥操作,以确保在任何时候只有一个客户端可以持有锁。)

总结

单机Redis
  1. 增加过期时间:解决应用宕机,锁无法释放的问题
  2. 增加线程ID,表示锁的归属:解决锁被其他线程释放的问题
  3. 增加watchdog,为锁自动续期:解决锁被自动清理的问题
集群Redis
  1. 向所有节点发送加锁请求,半数成功:解决主从切换后的数据不同步问题
  2. 增加请求超时时间,判断请求时间的消耗:解决网络延迟造成的锁过期问题

相关推荐

  1. Redis实现分布式

    2024-04-08 05:06:02       23 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-08 05:06:02       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-08 05:06:02       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-08 05:06:02       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-08 05:06:02       18 阅读

热门阅读

  1. html表单1:表单基础

    2024-04-08 05:06:02       10 阅读
  2. 【Verilog】工业级RTL代码风格推荐

    2024-04-08 05:06:02       13 阅读
  3. LeetCode | 数组 | 二分查找 | 69. x 的平方根【C++】

    2024-04-08 05:06:02       15 阅读
  4. 面试算法-138-移动零

    2024-04-08 05:06:02       13 阅读
  5. Kratos 基础学习记录

    2024-04-08 05:06:02       18 阅读
  6. hibernate检索方式

    2024-04-08 05:06:02       15 阅读
  7. 常见的几种字符串及其区别

    2024-04-08 05:06:02       17 阅读