redis分布式缓存原理从节点能写入key吗

使用redis实现分布式锁 - 蓝色的天空 - ITeye技术网站
博客分类:
在多节点的系统中,如何实现分布式锁机制,其中用redis来实现是很好的方法之一,我们先来看一下jedis包中,有个类名BinaryJedis,它有个方法如下:
public Long setnx(final byte[] key, final byte[] value) {
checkIsInMulti();
client.setnx(key, value);
return client.getIntegerReply();
它的意思是,设置这个key和value,前提是当前key不存在的情况下,还有一个重要前提,不存在多线程共享一个client,如果设置成功,结果会返回1,如果没有设置成功,结果返回0。
重点关注的地方是client.setnx(key,value), 到redis 的server端实现方法是原语,主要是充分利用到这一点来实现锁机制的,非常巧妙。
实现方式除了redis外还有很多的,例如zookeeper,数据库(充分使用事务的隔离机制来实现)等等,可以补充。
浏览: 5870 次
来自: 上海
这个代码很明显有读也有写,但是释放锁没有在finally里面写 ...
qifeifei 写道11楼的理解是在读前面也加上synchr ...
11楼的理解是在读前面也加上synchronized吗?对并发 ...
1、不是这个并发有问题,是你的理解有问题:你想实现读写互斥,你 ...
楼主的多线程还得多学习哈。。查看: 2045|回复: 4
用Redis实现分布式锁
认证徽章论坛徽章:274
分布式锁是一个在很多环境中非常有用的原语,它是不同进程互斥操作共享资源的唯一方法。有很多的开发库和博客描述如何使用Redis实现DLM(Distributed Lock Manager),但是每个开发库使用不同的方式,而且相比更复杂的设计与实现,很多库使用一些简单低可靠的方式来实现。
这篇文章尝试提供更标准的算法来使用Redis实现分布式锁。我们提出一种算法,叫做Relock,它实现了我们认为比vanilla单一实例方式更安全的DLM(分布式锁管理)。我们希望社区分析它并提供反馈,以做为更加复杂或替代设计的一个实现。 实现
在说具体算法之前,下面有一些具体的实现可供参考.
(Ruby实现).-
(PHP 实现).-
(Go 实现).-
(Java 实现).
认证徽章论坛徽章:274
安全和活跃性保证
从有效分布式锁的最小保证粒度来说,我们的模型里面只用了3个属性,具体如下:
1. 属性安全: 互斥行.在任何时候,只有一个客户端可以获得锁.
2. 活跃属性A: 死锁自由. 即使一个客户端已经拥用了已损坏或已被分割资源的锁,但它也有可能请求其他的锁.
3. 活跃属性B:容错. 只要大部分Redis节点可用, 客户端就可以获得和释放锁.
为何基于容错的实现还不够
要理解我们所做的改进,就要先分析下当前基于Redis的分布式锁的做法。
使用Redis锁住资源的最简单的方法是创建一对key-value值。利用Redis的超时机制,key被创建为有一定的生存期,因此它最终会被释放。而当客户端想要释放时,直接删除key就行了。
认证徽章论坛徽章:274
一般来说这工作得很好,但有个问题: 这是系统的一个单点。如果Redis主节点挂了呢?当然,我们可以加个子节点,主节点出问题时可以切换过来。不过很可惜,这种方案不可行,因为Redis的主-从复制是异步的,我们无法用其实现互斥的安全特性。
这明显是该模型的一种竞态条件:
1)客户端A在主节点获得了一个锁。
2)主节点挂了,而到从节点的写同步还没完成。
3)从节点被提升为主节点。
4)客户端B获得和A相同的锁。
注意,锁安全性被破坏了!
有时候,在某些情况下这反而工作得很好,例如在出错时,多个客户端可以获得同一个锁。如果这正好是你想要的,那就可以使用主-从复制的方案。否则,我们建议使用这篇文章中描述的方法。
认证徽章论坛徽章:274
单实例的正确实现方案
在尝试解决上文描述的单实例方案的缺陷之前,先让我们确保针对这种简单的情况,怎么做才是无误的,因为这种方案对某些程序而言也是可以接受的,而且这也是我们即将描述的分布式方案的基础。
为了获取锁,方法是这样的:SET resource_name my_random_value NX PX 30000复制代码这条指令将设置key的值,仅当其不存在时生效(NX选项), 且设置其生存期为30000毫秒(PX选项)。和key关联的value值是&my_random_value&。这个值在所有客户端和所有加锁请求中是必须是唯一的。
使用随机值主要是为了能够安全地释放锁,这要同时结合这么个处理逻辑:删除key值当且仅当其已存在并且其value值是我们所期待的。看看以下lua代码:if redis.call(&get&,KEYS[1]) == ARGV[1] then
& & return redis.call(&del&,KEYS[1])
else
& & return 0
end
复制代码
认证徽章论坛徽章:274
这么做很重要,可以避免误删其他客户端创建的锁。例如某个客户端获得了一个锁,但它的处理时长超过了锁的有效时长,之后它删除了这个锁,而此时这个锁可能又被其他客户端给获得了。仅仅做删除是不够安全的,很可能会把其他客户端的锁给删了。结合上面的代码,每个锁都有个唯一的随机值,因此仅当这个值依旧是客户端所设置的值时,才会去删除它。
那么应该怎样生成这个随机值呢?我们使用的是从/dev/urandom读取的20个字节,但你也可以找个更简单的方法,只要能满足任务就行。例如,可以使用/dev/urandom初始化RC4算法,然后用其产生随机数流。更简单的方法是组合unix时间戳和客户端ID, 这并不安全,但对很多环境而言也够用了。
我们所说的key的时间,是指”锁的有效时长“. 它代表两种情况,一种是指锁的自动释放时长,另一种是指在另一个客户端获取锁之前某个客户端占用这个锁的时长,这被限制在从锁获取后开始的一段时间窗口内。
现在我们已经有好的办法获取和释放锁了。在单实例非分布式系统中,只要保证节点没挂掉,这个方法就是安全的。那么让我们把这个概念扩展到分布式的系统中吧,那里可没有这种保证。
itpub.net All Right Reserved. 北京皓辰网域网络信息技术有限公司版权所有    
 北京市公安局海淀分局网监中心备案编号: 广播电视节目制作经营许可证:编号(京)字第1149号

我要回帖

更多关于 分布式缓存redis 的文章

 

随机推荐