专栏首页IT云清分布式锁系列--04关于分布式锁的选型分析02

分布式锁系列--04关于分布式锁的选型分析02

1.Redlock获取锁

Redlock获取锁的原理如下:

1.获取当前时间(毫秒数): t1。

2.按顺序依次向N个Redis节点执行获取锁的操作。这个获取操作跟前面基于单Redis节点的获取锁的过程相同,包含随机字符串my_random_value,也包含过期时间(比如PX 30000,即锁的有效时间 :T1)。为了保证在某个Redis节点不可用的时候算法能够继续运行,这个获取锁的操作还有一个超时时间(time out),它要远小于锁的有效时间(几十毫秒量级)。客户端在向某个Redis节点获取锁失败以后,应该立即尝试下一个Redis节点。这里的失败,应该包含任何类型的失败,比如该Redis节点不可用,或者该Redis节点上的锁已经被其它客户端持有(注:Redlock原文中这里只提到了Redis节点不可用的情况,但也应该包含其它的失败情况)。

3.计算整个获取锁的过程总共消耗了多长时间,计算方法是用当前时间:t2,减去第1步记录的时间:t1(即:t = t2 - t1)。如果客户端从大多数Redis节点(>= N/2+1)成功获取到了锁,并且获取锁总共消耗的时间没有超过锁的有效时间(lock validity time)(即:t < T ),那么这时客户端才认为最终获取锁成功;否则,认为最终获取锁失败。

4.如果最终获取锁成功了,那么这个锁的有效时间应该重新计算,它等于最初的锁的有效时间减去第3步计算出来的获取锁消耗的时间。即:T = T - t. 5.如果最终获取锁失败了(可能由于获取到锁的Redis节点个数少于N/2+1,或者整个获取锁的过程消耗的时间超过了锁的最初有效时间),那么客户端应该立即向所有Redis节点发起释放锁的操作(即前面介绍的Redis Lua脚本)。

这就是Redlock获取锁的过程。

2.释放锁

客户端向所有Redis节点发起释放锁的操作,不管这些节点当时在获取锁的时候成功与否。

在理论上,N各redis节点中的大多数节点可以正常工作时,就能保证Redlock正常工作,因为,我们前文讨论的单节点redis分布式锁在failover时锁失效的问题,就得到了避免。

3.问题

但是,此时,如果某个节点挂掉重启,会怎样呢?考虑下面的场景: 假设一共有5个Redis节点:A, B, C, D,E。设想发生了如下的事件序列:

1.客户端1成功锁住了A, B, C,获取锁成功(但D和E没有锁住)。

2.节点C崩溃重启了,但客户端1在C上加的锁没有持久化下来,丢失了。 3.节点C重启后,客户端2锁住了C, D, E,获取锁成功。

这样,客户端1和客户端2同时获得了锁(针对同一资源)。这个问题,和redsi的持久化有关。

4.延迟重启

在默认情况下,Redis的AOF持久化方式是每秒写一次磁盘(即执行fsync),因此最坏情况下可能丢失1秒的数据。为了尽可能不丢数据,Redis允许设置成每次修改数据都进行fsync,但这会降低性能。当然,即使执行了fsync也仍然有可能丢失数据(这取决于系统而不是Redis的实现)。所以,上面分析的由于节点重启引发的锁失效问题,总是有可能出现的。

为了应对这一问题,antirez又提出了延迟重启(delayed restarts)的概念。也就是说,一个节点崩溃后,先不立即重启它,而是等待一段时间再重启,这段时间应该大于锁的有效时间(lock validity time)。这样的话,这个节点在重启前所参与的锁都会过期,它在重启后就不会对现有的锁造成影响。

5.释放锁详解

在前文,我们说到,释放锁时:客户端向所有Redis节点发起释放锁的操作,不管这些节点当时在获取锁的时候成功与否。也就是说,即使当时向某个节点获取锁没有成功,在释放锁的时候也不应该漏掉这个节点。这是为什么呢?

设想这样一种情况,客户端发给某个Redis节点的获取锁的请求成功到达了该Redis节点,这个节点也成功执行了SET操作,但是它返回给客户端的响应包却丢失了。这在客户端看来,获取锁的请求由于超时而失败了,但在Redis这边看来,加锁已经成功了。因此,释放锁的时候,客户端也应该对当时获取锁失败的那些Redis节点同样发起请求。实际上,这种情况在异步通信模型中是有可能发生的:客户端向服务器通信是正常的,但反方向却是有问题的。

至此,我们看似解决了上一篇文章分布式锁系列–03关于分布式锁的选型分析中提到的第一个问题:由于redis的failover引起的安全问题。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 每周分享第4期

    我们都知道在JDK1.8的HotSpot虚拟机中已经没有永久代这个内存区域了,但许多人其实并不知道在JDK1.7的时候这项工作就在悄悄进行了。

    陈树义
  • 解析分布式锁之redis实现

    摘要:分布式架构设计如今在企业中被大量的应用,而在不同的分布式节点进行协同工作的时候,节点服务的时序、结果的正确性以及执行成本也成为了必须考虑的重要因素。其中竞...

    技术zhai
  • 消息中间件系列第2讲:如何进行消息队列选型?

    要做技术选型,那么必须对现今的各个消息中间件有个深入的理解才能做技术选型。否则别人问你,你为什么要用这个消息中间件,你说不出个所以然来,怎么做架构师呢?

    陈树义
  • C# Memory Cache 踩坑记录

    前些天公司服务器数据库访问量偏高,运维人员收到告警推送,安排我团队小伙伴排查原因.

    码农阿宇
  • 2018“金三”之一线互联网公司Java高级面试题总结

    3、知道字节码吗?字节码都有哪些?Integer x =5,int y =5,比较x =y 都经过哪些步骤?

    技术zhai
  • redis之django-redis

    使用中间件,经过一系列的认证等操作,如果内容在缓存中存在,则使用FetchFromCacheMiddleware获取内容并返回给用户, 当返回给用户之前,判断...

    人生不如戏
  • 【独家】终生受用的Redis高可用技术解决方案大全

    Redis 单副本,采用单个Redis节点部署架构,没有备用节点实时同步数据,不提供数据持久化和备份策略,适用于数据可靠性要求不高的纯缓存业务场景。

    技术zhai
  • R语言自带的数据文件

    R语言有大量的样本数据可以直接用来作为数据分析和挖掘案例,可以收藏着以后用! R:datasets >install.packages("datasets")...

    学到老
  • redis的安装与使用

     redis是当前比较热门的NOSQL系统之一,它是一个key-value存储系统。和Memcached类似,但很大程度补偿了memcached的不足,它支持存...

    人生不如戏
  • windows 下对redis安装和部署以及连接客户端与操作

    Redis官方并没有提供Redis的windows安装包,但在github上, 有相关的下载地址,如下: https://github.com/Servic...

    学到老

扫码关注云+社区

领取腾讯云代金券