Redisson实现分布式锁原理
redis官方的红锁解释https://redis.io/topics/distlock
一 Redis分布式锁原理
如图所示啊,石杉大佬画的redisson分布式锁原理。
大概总结下,保证我们的key落到一个集群里,并且加锁操作是基于lua脚本的原子性操作,对于锁延迟由watch dog控制。
具体可以看https://www.cnblogs.com/AnXinliang/p/10019389.html
二 普通Redis分布式锁可能出现多个系统加锁成功的现象
如果你对某个redis master实例,写入了myLock这种锁key的value,此时会异步复制给对应的master slave实例。但是这个过程中一旦发生redis master宕机,主备切换,redis slave变为了redis master。
接着就会导致,客户端2来尝试加锁的时候,在新的redis master上完成了加锁,而客户端1也以为自己成功加了锁。
此时就会导致多个客户端对一个分布式锁完成了加锁。
这时系统在业务语义上一定会出现问题,导致各种脏数据的产生。
所以这个就是redis cluster,或者是redis master-slave架构的主从异步复制导致的redis分布式锁的最大缺陷:在redis master实例宕机的时候,可能导致多个客户端同时完成加锁。
如果主动结构redis架构模式下,我们想保证完全一致,必须重写加锁的逻辑了,保证必须mater和slave同时加锁成功,我们整个加锁才是成功的
。
三 .redis的红锁---解决分布式Redis集群模式的加锁问题
上面的2是对于单个主从结构我们可以这样干,如果假设我们有多个相对独立的master,无slave呢?我们在其中一个master上加了🔐,然后它挂了岂不是我们的数据会在剩下的结点会重新加锁成功?
redis引入了红锁的概念:用Redis中的多个master实例,来获取锁,只有大多数
实例获取到了锁,才算是获取成功。
具体的红锁算法分为以下五步:
- 1.获取当前的时间(单位是毫秒)。
- 2.使用相同的key和随机值(随机值用于唯一关系客户端和key)在N个节点上请求锁。
这里获取锁的尝试时间要远远小于锁的超时时间,防止某个masterDown了,我们还在不断的获取锁,而被阻塞过长的时间。 - 3.只有在
大多数节点上
获取到了锁,而且总的获取时间小于锁的超时时间
的情况下,认为锁获取成功了。 - 如果锁获取成功了,那现在锁自动释放时间就是最初的锁释放时间减去之前获取锁所消耗的时间
- 如果锁获取失败了,不管是因为获取成功的节点的数目没有过半,还是因为获取锁的耗时超过了锁的释放时间,都会将已经设置了key的master上的key删除。
以上步骤来自redis 分布式锁的解释,如下
”相同的key和随机值(随机值用于唯一关系客户端和key)在N个节点上请求锁“
这里的随机数是什么?
这对于避免删除由另一个客户端创建的锁很重要。例如,客户端可能会获取锁,执行某些操作时被阻塞的时间超过锁的有效时间(密钥将过期的时间),然后移除已被其他客户端获取的锁。使用 justDEL
是不安全的,因为客户端可能会删除另一个客户端的锁。使用上面的脚本,每个锁都用一个随机字符串“签名”,所以只有当它仍然是客户端试图移除它时设置的锁才会被移除。
这个随机字符串应该是什么?我们假设它是 20 个字节/dev/urandom
,但您可以找到更便宜的方法使其对您的任务足够独特。例如,一个安全的选择是用 RC4 播种/dev/urandom
,并从中生成一个伪随机流。一个更简单的解决方案是使用具有微秒精度的 UNIX 时间戳,将时间戳与客户端 ID连接起来。它并不安全,但对于大多数环境来说可能就足够了。