乐趣区

关于java:Redisson-分布式锁源码-09RedLock-红锁的故事

前言

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 脚本实现锁开释:

if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end

为什么要设置随机值?

次要是为了避免锁被其余客户端删除。有这么一种状况:

  1. 客户端 A 取得了锁,还没有执行完结,然而锁超时主动开释了;
  2. 客户端 B 此时过去,是能够取得锁的,加锁胜利;
  3. 此时,客户端 A 执行完结了,要去开释锁,如果不比照随机值,就会把客户端 B 的锁给开释了。

当然后面看过 Redisson 的解决,这个 my_random_value 寄存的是 UUID:ThreadId 组合成的一个相似 931573de-903e-42fd-baa7-428ebb7eda80:1 的字符串。

当锁遇到故障转移

单实例必定不是很牢靠吧?加锁胜利之后,后果 Redis 服务宕机了,这不就凉凉~

这时候会提出来将 Redis 主从部署。即便是主从,也是存在偶合的!

主从构造中存在显著的竞态:

  1. 客户端 A 从 master 获取到锁
  2. 在 master 将锁同步到 slave 之前,master 宕掉了。
  3. slave 节点被升级为 master 节点
  4. 客户端 B 获得了同一个资源被客户端 A 曾经获取到的另外一个锁。平安生效!

有时候程序就是这么巧,比如说正好一个节点挂掉的时候,多个客户端同时取到了锁。如果你能够承受这种小概率谬误,那用这个基于复制的计划就齐全没有问题。

那我应用集群呢?

如果还记得后面的内容,应该是晓得对集群进行加锁的时候,其实是通过 CRC16 的 hash 函数来对 key 进行取模,将后果路由到事后调配过 slot 的相应节点上。

发现 其实还是发到单个节点上的

RedLock 概念

这时候 Redis 作者提出了 RedLock 的概念

总结一下就是对集群的每个节点进行加锁,如果大多数(N/2+1)加锁胜利了,则认为获取锁胜利。

RedLock 的问题

看着 RedLock 如同是解决问题了:

  1. 客户端 A 锁住了集群的大多数(一半以上);
  2. 客户端 B 也要锁住大多数;
  3. 这里必定会抵触,所以 客户端 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 齐全是 RedissonMultiLock 的子类,只是重写了 failedLocksLimit 办法,保障半数以上加锁胜利即可。

所以这三个 key,是须要用户来保障扩散在不同的节点上的。

https://github.com/redisson/r…

在 Redisson 的 issues 也有同样的小伙伴提出这个问题,相干开发者给出的回复是用户来保障 key 扩散在不同的 master 上。

https://github.com/redisson/r…

更有小伙伴提出应用 5 个客户端。

那我应用 5 个单节点的客户端,而后再应用红锁,听着如同是能够的,并且 RedissonRedLock 能够这样应用。

然而那和 Redis 集群还有啥关系啊!

所以仍然没有解决我的问题,还是须要用户本人来“手工定位锁”。

手工定位锁,这个…… 我思考了下,还是不必 RedLock 吧!

当然 DarrenJiang1990 同学应该是怀着打破砂锅问到底的情绪,又来了一篇 issue。

https://github.com/redisson/r…

意思就是:不要敞开我的 issues,在 #2436 中说能够“手工定位锁”,然而我要怎么手工定位锁。

起初这个 issue 在 10 月才回复。

2、RedissonRedLock 被弃用

是的,没有看错,当初 RedissonRedLock 曾经被启用了。

如果是看的英文文档,就会发现:

而中文文档,应该是没有及时更新。

来看看更新记录:

再找一找 issue:

https://github.com/redisson/r…

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:偏心锁排队加锁
退出移动版