前言
RedLock 红锁,是分布式锁中必须要理解的一个概念。
所以本文会先介绍什么是 RedLock,当大家对 RedLock 有一个根本的理解。而后再看 Redisson 中是如何实现 RedLock 的。
在文章结尾先阐明 Redisson RedLock 倡议不要应用!!!
在文章结尾先阐明 Redisson RedLock 倡议不要应用!!!
在文章结尾先阐明 Redisson RedLock 倡议不要应用!!!
重要的事件反复三遍!
什么是 RedLock?
RedLock,这块能够从网上搜到很多材料,本文也简略介绍下,当做扫盲。
单实例加锁
SET resource_name my_random_value NX PX 30000
对于单实例 Redis 只须要应用这个命令即可。
- NX:仅在不存在 key 的时候能力被执行胜利;
- PX:生效工夫,传入 30000,就是 30s 后主动开释锁;
- my_random_value:就是随机值,能够是线程号之类的。次要是为了更平安的开释锁,开释锁的时候应用脚本通知 Redis: 只有 key 存在并且存储的值和我指定的值一样能力删除胜利。
能够通过以下 Lua 脚本实现锁开释:
<code class="lua">if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end
为什么要设置随机值?
次要是为了避免锁被其余客户端删除。有这么一种状况:
- 客户端 A 取得了锁,还没有执行完结,然而锁超时主动开释了;
- 客户端 B 此时过去,是能够取得锁的,加锁胜利;
- 此时,客户端 A 执行完结了,要去开释锁,如果不比照随机值,就会把客户端 B 的锁给开释了。
当然后面看过 Redisson 的解决,这个 my_random_value 寄存的是 UUID:ThreadId
组合成的一个相似 931573de-903e-42fd-baa7-428ebb7eda80:1
的字符串。
当锁遇到故障转移
单实例必定不是很牢靠吧?加锁胜利之后,后果 Redis 服务宕机了,这不就凉凉~
这时候会提出来将 Redis 主从部署。即便是主从,也是存在偶合的!
主从构造中存在显著的竞态:
- 客户端 A 从 master 获取到锁
- 在 master 将锁同步到 slave 之前,master 宕掉了。
- slave 节点被升级为 master 节点
- 客户端 B 获得了同一个资源被客户端 A 曾经获取到的另外一个锁。平安生效!
有时候程序就是这么巧,比如说正好一个节点挂掉的时候,多个客户端同时取到了锁。如果你能够承受这种小概率谬误,那用这个基于复制的计划就齐全没有问题。
那我应用集群呢?
如果还记得后面的内容,应该是晓得对集群进行加锁的时候,其实是通过 CRC16 的 hash 函数来对 key 进行取模,将后果路由到事后调配过 slot 的相应节点上。
发现其实还是发到单个节点上的!
RedLock 概念
这时候 Redis 作者提出了 RedLock 的概念
总结一下就是对集群的每个节点进行加锁,如果大多数(N/2+1)加锁胜利了,则认为获取锁胜利。
RedLock 的问题
看着 RedLock 如同是解决问题了:
- 客户端 A 锁住了集群的大多数(一半以上);
- 客户端 B 也要锁住大多数;
- 这里必定会抵触,所以 客户端 B 加锁失败。
那理论解决问题了么?
举荐大家浏览两篇文章:
- Martin Kleppmann:How to do distributed locking
- Salvatore(Redis 作者):Is Redlock safe?
最终,两方各抒己见,没有得出结论。
鉴于本文次要是剖析 Redisson 的 RedLock,就不做额定赘述,感兴趣的小伙伴能够本人浏览。
Redisson 中 RedLock 源码
这里会简要剖析一下 Redisson 中 RedLock 的源码,而后会介绍为什么文章结尾不倡议大家应用 Redisson 的 RedLock。
应用形式
乍一看,感觉和联锁 MultiLock 的应用形式很像啊!
实际上就是很像,RedissonRedLock 齐全是 RedissonMultiLock 的子类嘛!
只不过是重写 failedLocksLimit
办法。
在 MultiLock 中,要所有的锁都锁胜利才能够。
在 RedLock 中,要一半以上的锁胜利。
残余局部源码都和 MultiLock 一样,就不在反复形容了。
Redisson 中 RedLock 的问题
1、加锁 key 的问题
浏览源码之前,有一个很大的疑难,我加锁 lock1、lock2、lock3,然而 RedissonRedLock 是如何保障这三个 key 是在归属于 Redis 集群中不同的 master 呢?
因为依照 RedLock 的实践,是须要在半数以上的 master 节点加锁胜利。
浏览完源码之后,发现 RedissonRedLock 齐全是 RedissonMul来源gao@dai!ma.com搞$代^码网tiLock 的子类,只是重写了 failedLocksLimit
办法,保障半数以上加锁胜利即可。
所以这三个 key,是须要用户来保障扩散在不同的节点上的。
在 Redisson 的 issues 也有同样的小伙伴提出这个问题,相干开发者给出的回复是用户来保障 key 扩散在不同的 master 上。
更有小伙伴提出应用 5 个客户端。
那我应用 5 个单节点的客户端,而后再应用红锁,听着如同是能够的,并且 RedissonRedLock 能够这样应用。
然而那和 Redis 集群还有啥关系啊!
所以仍然没有解决我的问题,还是须要用户本人来“手工定位锁”。
手工定位锁,这个…… 我思考了下,还是不必 RedLock 吧!
当然 DarrenJiang1990 同学应该是怀着打破砂锅问到底的情绪,又来了一篇 issue。
https://github.com/redisson/r…
意思就是:不要敞开我的 issues,在 #2436 中说能够“手工定位锁”,然而我要怎么手工定位锁。
起初这个 issue 在 10 月才回复。
2、RedissonRedLock 被弃用
是的,没有看错,当初 RedissonRedLock 曾经被启用了。
如果是看的英文文档,就会发现:
而中文文档,应该是没有及时更新。
来看看更新记录:
再找一找 issue:
Redisson 的开发者认为 Redis 的红锁也存在争议(前文介绍的那个争议),然而为了保障可用性,RLock 对象执行的每个 Redis 命令执行都通过 Redis 3.0 中引入的 WAIT 命令进行同步。
WAIT 命令会阻塞以后客户端,直到所有以前的写命令都胜利的传输并被指定数量的正本确认。如果达到以毫秒为单位指定的超时,则即便尚未达到指定数量的正本,该命令也会返回。
WAIT 命令同步复制也并不能保障强一致性,不过在主节点宕机之后,只不过会尽可能的抉择最佳的正本(slaves)
源码在这一部分。
看源码,同时发送了一个 WAIT 1 1000
到 Redis。
论断
Redisson RedLock 是基于联锁 MultiLock 实现的,然而应用过程中须要本人判断 key 落在哪个节点上,对使用者不是很敌对。
Redisson RedLock 曾经被弃用,间接应用一般的加锁即可,会基于 wait 机制将锁同步到从节点,然而也并不能保障一致性。仅仅是最大限度的保障一致性。
相干举荐
- Redisson 分布式锁源码 08:MultiLock 加锁与锁开释
- Redisson 分布式锁源码 07:偏心锁开释
- Redisson 分布式锁源码 06:偏心锁排队加锁