`

分布式锁Redlock

阅读更多
好文章:https://blog.csdn.net/hh1sdfsf56456/article/details/79474434

分布式锁,存在无法解决的问题,一起回顾如下
1、为了提高单redis的可用性,给master挂了一个从slave节点,因为主从复制是异步的,会出现不同客户端同时获取锁的情况
客户端1在master中获得了锁,
在锁同步到slave之前,master宕机,还未来得及将锁同步到slave
slave升级为master
客户端2在新的master中获取了锁
这样客户端1、客户端2就同时持有了同一个资源的锁

2、客户端1获取锁,因网络延时,客户端长时间阻塞,锁过期,这时客户端2获取锁,与此同时客户端1的网络恢复正常,这就导致两个客户端可同时访问共享资源。
备注:有两种情况会引发阻塞
情况1:客户端跟redis通信的问题,
情况2:客户端跟共享资源服务器交互延时


那么接下来我看看Redlock是否能解决上述两个问题

一、分布式锁Redlock
antirez因为上述问题提出了新的分布式锁的算法Redlock,它基于N个完全独立的Redis节点(通常情况下N可以设置成5)。

运行Redlock算法的客户端依次执行下面各个步骤,来完成获取锁的操作:

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

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

如果最终获取锁成功了,那么这个锁的有效时间应该重新计算,它等于最初的锁的有效时间减去第3步计算出来的获取锁消耗的时间。

如果最终获取锁失败了(可能由于获取到锁的Redis节点个数少于N/2+1,或者整个获取锁的过程消耗的时间超过了锁的最初有效时间),那么客户端应该立即向所有Redis节点发起释放锁的操作(即前面介绍的Redis Lua脚本)。

当然,上面描述的只是获取锁的过程,而释放锁的过程比较简单:客户端向所有Redis节点发起释放锁的操作,不管这些节点当时在获取锁的时候成功与否。

二、Redlock存在的问题

由于N个Redis节点中的大多数能正常工作就能保证Redlock正常工作,因此理论上它的可用性更高。我们前面讨论的单Redis节点的分布式锁在failover的时候锁失效的问题,在Redlock中不存在了(解决了遗留问题1),但如果有节点发生崩溃重启,还是会对锁的安全性有影响的。具体的影响程度跟Redis对数据的持久化程度有关。
根据上述提出的算法,当N个节点中有一个节点宕机,仍然存在锁的安全性问题。具体的影响跟redis的持久化程度有关

假设一共有5个Redis节点:A, B, C, D, E。设想发生了如下的事件序列:

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

这样,客户端1和客户端2同时获得了锁(针对同一资源)。

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

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

关于Redlock还有一点细节值得拿出来分析一下:

antirez在算法描述中特别强调:在最后释放锁的时候,客户端应该向所有Redis节点发起释放锁的操作。也就是说,即使当时向某个节点获取锁没有成功,在释放锁的时候也不应该漏掉这个节点。

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

三、其它问题
1、仍然存在开篇我们提到的第2个问题:客户端长时间阻塞,导致获得的锁释放,访问的共享资源不受保护的问题。
2、在Redlock的算法中,我们可以看到第3步,当获取锁耗时太多,留给客户端的访问共享资源的时间很短,这种情况若来不及操作,是不是要释放锁呢?且到底剩下多少时间才算短?这又是一个选择难题。
3、Redlock算法对时钟依赖性太强,若N个节点中的某个节点发生时间跳跃,也可能会引此而引发锁安全性问题。
分享到:
评论

相关推荐

    redlock-py, 在 python 中,Redis分布式锁.zip

    redlock-py, 在 python 中,Redis分布式锁 redlock - python 中的分布式锁这个 python 库实现了基于redis的分布式锁管理器算法( ) 。要创建锁定管理器:dlm = Redlock([{"host":"localhost","port":

    案例实战-SpringBoot整合Redisson实现RedLock分布式锁同步

    SpringBoot整合Redisson实现RedLock分布式锁同步源码包

    redlock-rb, 在 ruby 中,基于Redlock的分布式锁实现.zip

    redlock-rb, 在 ruby 中,基于Redlock的分布式锁实现 redlock ruby - 中的分布式锁这个 ruby 库实现了基于redis的分布式锁管理器算法( ) 。要创建锁定管理器:dlm = Redlock.new("redis://127.0.0.1:6379","redis

    javalruleetcode-redis-redlock:Redis数据类型的使用场景、Redisson分布式锁

    java lru leetcode 一、Redis数据类型使用场景 1. 两个小细节 (1)命令不区分大小写,而 key 区分大小写。 (2)help @ 可以快速查看命令。 # 1: 命令不区分大小写,而 `key` 区分大小写 ...increment

    Redis分布式锁存在的问题及解决方案(值得珍藏)

    Redis分布式锁在实现跨进程、跨机器的互斥访问时,虽功能强大,但也存在一些常见问题。这些问题主要源于网络延迟、系统时钟误差以及Redis自身的特性。 一个典型问题是锁的"死锁"现象,即因进程意外终止或网络故障,...

    RedLock分布式锁

    RedLock分布式锁

    redis和zookeeper实现分布式锁的区别

    只要创建好一个分布式锁,就要不断轮循这个锁什么时候释放。 zk只会对已经创建分布式锁的系统进行创建监听,所以性能消耗很小 2、运行出现错误 redis创建锁的节点如果挂了,那就只能等待超时才能释放锁 zk因为是创建...

    Javas使用Redlock实现分布式锁过程解析

    主要介绍了Javas使用Redlock实现分布式锁过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    redlock-rb:Redlock是Ruby中基于redis的分布式锁实现

    Redlock-使用Redis的Ruby分布式锁。 在许多环境中,不同的进程需要以互斥的方式使用共享资源进行操作时,分布式锁是非常有用的原语。 有许多库和博客文章描述了如何使用Redis实现DLM(分布式锁管理器),但是每个...

    redisson分布式锁源码笔记

    1、详述分布式环境下遇到的问题 2、redisson可重入锁源码 3、RLock#lock()方法源码解析 ...11、RedLock锁源码剖析 12、RedLock可能存在的问题 13、MultiLock加锁逻辑 14、公平锁加锁逻辑 15、锁超时及自动释放

    基于 redlock的java支持redis的唯一实现支持多实例集群的分布式锁

    支持多实例集群,分布式锁,spring cache 整合,session集群,消息队列,对象存储。redisson是java支持redis的redlock的唯一实现, 集成该项目后只需要极少的配置.就能够使用redisson的全部功能. 目前支持 集群模式,云托管...

    python如何使用Redis构建分布式锁

    这篇文章主要介绍了python如何使用Redis构建分布式锁,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在实际应用场景中,我们可能有多个worker,可能在一台机器...

    redlock-php:PHP中的Redis分布式锁

    RedLock – PHP中的Redis分布式锁 基于 该库实现了的基于Redis的分布式锁管理器算法。 要创建锁管理器: $ servers = [ [ '127.0.0.1' , 6379 , 0.01 ], [ '127.0.0.1' , 6389 , 0.01 ], [ '127.0.0.1' , 6399...

    liuyuqin1991#polaris#Redlock分布式锁1

    它可以保证以下特性:安全特性:互斥访问,即永远只有一个 client 能拿到锁避免死锁:最终 client 都可能拿到锁,不会出现死锁的情况,即使原本锁住某资源

    redlock-nodejs:用于Redis的分布式锁定算法,请参阅http

    多重锁 用于Redis的分布式锁定算法,请参见 这是实验性软件,使用风险自负。 安装 npm install multiredlock 用法 一个简单的例子,可以在example.js找到: var Redlock = require ( 'multiredlock' ) ; var...

    redis-distlock:使用Redis的分布式锁管理器

    这是使用Redis进行分布式锁管理的Redlock算法的实现。 它启用轻量级分布式锁,以防止 cronjob 溢出,帮助处理队列,其中许多 worker 一次只能运行一个,以及类似的情况。 注意:这至少需要 Redis 2.6.12 版,它为...

    node-redlock:一个Node.js Redlock实现,用于分布式,高可用性的Redis锁

    这是分布式分布式锁的算法的node.js实现。 它在单redis和多redis环境中均提供了有力的保证,并通过使用多个独立的Redis实例或群集来提供容错能力。 高可用性建议 至少使用3个独立的服务器或群集 大多数安装使用奇数...

    redlocker-php:PHP中的Redlock风格Locker分布式锁

    PHP中的Redlock风格Locker分布式锁 基于 、 和 。 这个库使用 node.js服务器实现了的分布式锁管理器算法。 储物柜特点: 以毫秒精度锁定超时: 等待获得锁定的超时时间。 释放前保持锁定的超时时间。 无轮询:...

    基于 Redis 官方分布式锁文章的 Python +源代码+文档说明

    我认为 Redis 官方提出的 Redlock 是一种很有意义的分布式锁实现方式,接着参考了 SPSCommerce 团队的实现 编写了你现在看到的这段代码; 在 Redlock 的 Python 范例的基础上,我做了一些小的改动,让它更贴近实际...

    RedLock.net, 在 C# 中,Redlock算法的实现.zip

    RedLock.net, 在 C# 中,Redlock算法的实现 RedLock.net 一种 Redlock分布式锁算法的实现。利用优秀的 StackExchange.Redis 插件库。分布式锁对于确保在任何给定时间( 即使这些进程在不同的机器上运行) 只使用一个...

Global site tag (gtag.js) - Google Analytics