赞
踩
RedLock 红锁,是分布式锁中必须要了解的一个概念。
所以本文会先介绍什么是 RedLock,当大家对 RedLock 有一个基本的了解。然后再看 Redisson 中是如何实现 RedLock 的。
在文章开头先说明 Redisson RedLock 建议不要使用!!!
在文章开头先说明 Redisson RedLock 建议不要使用!!!
在文章开头先说明 Redisson RedLock 建议不要使用!!!
重要的事情重复三遍!
RedLock,这块可以从网上搜到很多资料,本文也简单介绍下,当做扫盲。
SET resource_name my_random_value NX PX 30000
对于单实例 Redis 只需要使用这个命令即可。
可以通过以下 Lua 脚本实现锁释放:
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
为什么要设置随机值?
主要是为了防止锁被其他客户端删除。有这么一种情况:
当然前面看过 Redisson 的处理,这个 my_random_value 存放的是 UUID:ThreadId
组合成的一个类似 931573de-903e-42fd-baa7-428ebb7eda80:1
的字符串。
单实例肯定不是很可靠吧?加锁成功之后,结果 Redis 服务宕机了,这不就凉凉~
这时候会提出来将 Redis 主从部署。即使是主从,也是存在巧合的!
主从结构中存在明显的竞态:
有时候程序就是这么巧,比如说正好一个节点挂掉的时候,多个客户端同时取到了锁。如果你可以接受这种小概率错误,那用这个基于复制的方案就完全没有问题。
那我使用集群呢?
如果还记得前面的内容,应该是知道对集群进行加锁的时候,其实是通过 CRC16 的 hash 函数来对 key 进行取模,将结果路由到预先分配过 slot 的相应节点上。
发现其实还是发到单个节点上的!
这时候 Redis 作者提出了 RedLock 的概念
总结一下就是对集群的每个节点进行加锁,如果大多数(N/2+1)加锁成功了,则认为获取锁成功。
看着 RedLock 好像是解决问题了:
那实际解决问题了么?
推荐大家阅读两篇文章:
Martin Kleppmann:How to do distributed locking
Salvatore(Redis 作者):Is Redlock safe?
最终,两方各持己见,没有得出结论。
鉴于本文主要是分析 Redisson 的 RedLock,就不做额外赘述,感兴趣的小伙伴可以自己阅读。
这里会简要分析一下 Redisson 中 RedLock 的源码,然后会介绍为什么文章开头不建议大家使用 Redisson 的 RedLock。
乍一看,感觉和联锁 MultiLock 的使用方式很像啊!
实际上就是很像,RedissonRedLock 完全是 RedissonMultiLock 的子类嘛!
只不过是重写 failedLocksLimit
方法。
在 MultiLock 中,要所有的锁都锁成功才可以。
在 RedLock 中,要一半以上的锁成功。
剩余部分源码都和 MultiLock 一样,就不在重复描述了。
阅读源码之前,有一个很大的疑问,我加锁 lock1、lock2、lock3,但是 RedissonRedLock 是如何保证这三个 key 是在归属于 Redis 集群中不同的 master 呢?
因为按照 RedLock 的理论,是需要在半数以上的 master 节点加锁成功。
阅读完源码之后,发现 RedissonRedLock 完全是 RedissonMultiLock 的子类,只是重写了 failedLocksLimit
方法,保证半数以上加锁成功即可。
所以这三个 key,是需要用户来保证分散在不同的节点上的。
https://github.com/redisson/redisson/issues/2436
在 Redisson 的 issues 也有同样的小伙伴提出这个问题,相关开发者给出的回复是用户来保证 key 分散在不同的 master 上。
https://github.com/redisson/redisson/issues/2127
更有小伙伴提出使用 5 个客户端。
那我使用 5 个单节点的客户端,然后再使用红锁,听着好像是可以的,并且 RedissonRedLock 可以这样使用。
但是那和 Redis 集群还有啥关系啊!
所以依然没有解决我的问题,还是需要用户自己来“手工定位锁”。
手工定位锁,这个…… 我考虑了下,还是不用 RedLock 吧!
当然 DarrenJiang1990 同学应该是怀着打破砂锅问到底的心情,又来了一篇 issue。
https://github.com/redisson/redisson/issues/2437
意思就是:不要关闭我的 issues,在 #2436 中说可以“手工定位锁”,但是我要怎么手工定位锁。
后来这个 issue 在 10 月才回复。
是的,没有看错,现在 RedissonRedLock 已经被启用了。
如果是看的英文文档,就会发现:
而中文文档,应该是没有及时更新。
来看看更新记录:
再找一找 issue:
https://github.com/redisson/redisson/issues/2669
Redisson 的开发者认为 Redis 的红锁也存在争议(前文介绍的那个争议),但是为了保证可用性,RLock 对象执行的每个 Redis 命令执行都通过 Redis 3.0 中引入的 WAIT 命令进行同步。
WAIT 命令会阻塞当前客户端,直到所有以前的写命令都成功的传输并被指定数量的副本确认。如果达到以毫秒为单位指定的超时,则即使尚未达到指定数量的副本,该命令也会返回。
WAIT 命令同步复制也并不能保证强一致性,不过在主节点宕机之后,只不过会尽可能的选择最佳的副本(slaves)
源码在这一部分。
看源码,同时发送了一个 WAIT 1 1000
到 Redis。
Redisson RedLock 是基于联锁 MultiLock 实现的,但是使用过程中需要自己判断 key 落在哪个节点上,对使用者不是很友好。
Redisson RedLock 已经被弃用,直接使用普通的加锁即可,会基于 wait 机制将锁同步到从节点,但是也并不能保证一致性。仅仅是最大限度的保证一致性。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。