一边翻译手册一边创作的一篇关于Redis的学习文档,发上来与大家分享:
============================================
Redis有一系列的命令,特点是以NX结尾,NX是Not eXists的缩写,如SETNX命令就应该理解为:SET if Not eXists。这系列的命令非常有用,这里讲使用SETNX来实现分布式锁。
利用SETNX非常简单地实现分布式锁。例如:某客户端要获得一个名字foo的锁,客户端使用下面的命令进行获取:
SETNX lock.foo <current Unix time + lock timeout + 1>
上面的锁定逻辑有一个问题:如果一个持有锁的客户端失败或崩溃了不能释放锁,该怎么解决?我们可以通过锁的键对应的时间戳来判断这种情况是否发生了,如果当前的时间已经大于lock.foo的值,说明该锁已失效,可以被重新使用。
发生这种情况时,可不能简单的通过DEL来删除锁,然后再SETNX一次,当多个客户端检测到锁超时后都会尝试去释放它,这里就可能出现一个竞态条件,让我们模拟一下这个场景:
这样一来,C1,C2都拿到了锁!问题大了!
幸好这种问题是可以避免D,让我们来看看C3这个客户端是怎样做的:
注意:为了让分布式锁的算法更稳键些,持有锁的客户端在解锁之前应该再检查一次自己的锁是否已经超时,再去做DEL操作,因为可能客户端因为某个耗时的操作而挂起,操作完的时候锁因为超时已经被别人获得,这时就不必解锁了。
根据上面的代码,我写了一小段Fake代码来描述使用分布式锁的全过程:
是的,要想这段逻辑可以重用,使用python的你马上就想到了Decorator,而用Java的你是不是也想到了那谁?AOP + annotation?行,怎样舒服怎样用吧,别重复代码就行。
--
您收到此信息是由于您订阅了 珠三角技术沙龙(http://techparty.org) 论坛。
要在此论坛发帖,请发电子邮件到 guangzhou-...@googlegroups.com
要退订此论坛,请发邮件至
guangzhou-tech-p...@googlegroups.com
更多选项,请通过
http://groups.google.com/group/guangzhou-tech-party?hl=zh-CN 访问该论坛
自己检查超市和自己del并不是原子操作吧,这是有问题的呀。
--
-------------------------------------------------------------------------learn log: http://me.boolsir.commy life log: http://www.boolsir.com-------------------------------------------------------------------------
DEL语句不一定被执行,要根据情况:- 如果未超时,说明当前的客户端是持有锁的,进行DEL操作是在锁内执行的,所以可以看作是原子的。
在 2011年7月13日 下午10:57,jeff <je...@fallever.com> 写道:
> 是的,这的确并不是Redis独有,实际上通过锁定一个文件也可以达到同样的目的。
> 不过相比之下,Redis由于提供了非常丰富和强大的原子操作,使用用它来达到这个目的时可以写少很多代码(代码少的好处大家都懂的)。正式的代码的量与文中的伪代码量基本相等的。
> 2011/7/13 Tim <iso...@gmail.com>
>>
>> 这个不是Redis独有的优势,memcached
>> 也可以的,http://timyang.net/programming/memcache-mutex/
俺的直觉问题:
这样只能作同一主机的不同进程/线程的锁吧?
Redis 自个儿不是分布式的哪,这怎么分布式锁呢?
jeff 说到:
2011-07-13 @ 10:11 下午
我所定义的分布式锁是指支持分布式应用(多个进程,多个主机)共享的锁。而不是说锁本身是分布式的。
锁本身若是分布式,那它的可靠性也就值得商榷了。。
我使用Redis这个机制实现锁,就是为了可以让程序可以实现分布式部署啊。
对于 redis 使用方式的挖掘,无论如何是得肯定的,
- 俺的疑问也是从实际部署出发的:
- 基于这一自身不分布的"分布式锁"的其它应用,是否可以分布式部署在不同主机
- 然后通过 http 接口来共同调度一些业务?
- 如果是这样,和 "RestMQ"
http://www.restmq.com/
有什么差别?
>> 2011/7/13 jeff <je...@fallever.com>
>>>
>>> 一边翻译手册一边创作的一篇关于Redis的学习文档,发上来与大家分享:
>>>
...
--
人生苦短, Pythonic! 冗余不做,日子甭过!备份不做,十恶不赦!
俺: http://about.me/zoom.quiet
哲: http://www.zeuux.org/home/zoomquiet
豆: http://www.douban.com/group/zoomquiet
书: http://code.google.com/p/openbookproject
营: http://code.google.com/p/kcpycamp/wiki/PythoniCamp
文字协议: http://creativecommons.org/licenses/by-sa/2.5/cn/
既然是转发也应该给出自个儿的URI 哪
http://www.jeffkit.info/2011/07/1000/
> 是的,这的确并不是Redis独有,实际上通过锁定一个文件也可以达到同样的目的。俺的直觉问题:
> 不过相比之下,Redis由于提供了非常丰富和强大的原子操作,使用用它来达到这个目的时可以写少很多代码(代码少的好处大家都懂的)。正式的代码的量与文中的伪代码量基本相等的。
> 2011/7/13 Tim <iso...@gmail.com>
>>
>> 这个不是Redis独有的优势,memcached
>> 也可以的,http://timyang.net/programming/memcache-mutex/
这样只能作同一主机的不同进程/线程的锁吧?
Redis 自个儿不是分布式的哪,这怎么分布式锁呢?
jeff 说到:
2011-07-13 @ 10:11 下午
我所定义的分布式锁是指支持分布式应用(多个进程,多个主机)共享的锁。而不是说锁本身是分布式的。
锁本身若是分布式,那它的可靠性也就值得商榷了。。
我使用Redis这个机制实现锁,就是为了可以让程序可以实现分布式部署啊。
对于 redis 使用方式的挖掘,无论如何是得肯定的,
- 俺的疑问也是从实际部署出发的:
- 基于这一自身不分布的"分布式锁"的其它应用,是否可以分布式部署在不同主机
- 然后通过 http 接口来共同调度一些业务?
...
--
人生苦短, Pythonic! 冗余不做,日子甭过!备份不做,十恶不赦!
俺: http://about.me/zoom.quiet
哲: http://www.zeuux.org/home/zoomquiet
豆: http://www.douban.com/group/zoomquiet
书: http://code.google.com/p/openbookproject
营: http://code.google.com/p/kcpycamp/wiki/PythoniCamp
文字协议: http://creativecommons.org/licenses/by-sa/2.5/cn/
--
您收到此信息是由于您订阅了 珠三角技术沙龙(http://techparty.org) 论坛。
要在此论坛发帖,请发电子邮件到 guangzhou-...@googlegroups.com
要退订此论坛,请发邮件至
guangzhou-tech-p...@googlegroups.com
更多选项,请通过
http://groups.google.com/group/guangzhou-tech-party?hl=zh-CN 访问该论坛
- 有点明白了,俺想差了
- Jeff 这是要直接增强 redis 的内存数据管理策略
+ 通过分布式的原生锁调度服务
+ 来直接对分布式的同类数据缓存的 redis 实例进行协同
+ 利用 redis 自身,完成 memcache 天然的分布式缓存機能
是也乎?
这的确很好用哪,省得 app 自个儿管理怎么同步/清理神马的了...
期待正式插件释放,以及教程文档...
>>
>> - 然后通过 http 接口来共同调度一些业务?
>
> 通过Http接口来调度业务,似乎与“锁”的使用场景没太大关系?
>
>>
>> - 如果是这样,和 "RestMQ"
>> http://www.restmq.com/
>> 有什么差别?
>
> RestMQ提供的是Rest化的消息队列方案,有点像HttpSQS了,但这是队列,从队列的几种使用模式上来讲都不能用来当锁啊。我认为这是两个不同的概念了哇。
...
...
>>
>> - 然后通过 http 接口来共同调度一些业务?
>
> 通过Http接口来调度业务,似乎与"锁"的使用场景没太大关系?
>
>>
>> - 如果是这样,和 "RestMQ"
>> http://www.restmq.com/
>> 有什么差别?
>
> RestMQ提供的是Rest化的消息队列方案,有点像HttpSQS了,但这是队列,从队列的几种使用模式上来讲都不能用来当锁啊。我认为这是两个不同的概念了哇。
--
人生苦短, Pythonic! 冗余不做,日子甭过!备份不做,十恶不赦!
俺: http://about.me/zoom.quiet
哲: http://www.zeuux.org/home/zoomquiet
豆: http://www.douban.com/group/zoomquiet
书: http://code.google.com/p/openbookproject
营: http://code.google.com/p/kcpycamp/wiki/PythoniCamp
文字协议: http://creativecommons.org/licenses/by-sa/2.5/cn/
--
您收到此信息是由于您订阅了 珠三角技术沙龙(http://techparty.org) 论坛。
要在此论坛发帖,请发电子邮件到 guangzhou-...@googlegroups.com
要退订此论坛,请发邮件至
guangzhou-tech-p...@googlegroups.com
更多选项,请通过
http://groups.google.com/group/guangzhou-tech-party?hl=zh-CN 访问该论坛
坚持和删除不是原子的呀,没有一个checkanddel原子操作。
另外,我看你后面提及时间设置长一些,更加保险 但是完美的解决方案是不依赖多一点时间来保证什么的呀。
如果没有cad操作,那c的时候没超市,试图去删除,但实际上 锁被别人取了,然后你删到的是别人的锁哦。
from my phone.
手机上面的消息竟然没有发出,难道是要改host才能访问了?我在这里重新说一遍吧,check_expiration,和del不是原子操作。如果没有CAD操作的话,那可能出现如下的情况:1. 我自己检查超时,确定没超时。a. 别人来了,发现你超时了,还没释放,那清掉。加上自己的锁。2. 我自己del锁foo
b. 这下好了,别人在做事情,不知道自己的锁被删除了,同时有另外一个过来拿锁,成功。
这是你预想的结果么?
我觉得这是关键的问题。不过不清楚Jeff兄的实际应用是什么,可否讲下?