有些分布式场景会有分布式锁的需求,可以为了原子操作,也可能为了性能的原因,不管是分布式锁市面是有不少解决方法的,比如etcd、consul、zookeeper… 初次之外redis这样的nosql也是可以实现分布式锁的。  python党喜欢用redis、etcd、consul来搞。   java这帮人更喜欢用zookeeper来实现分布式锁,zookeeper做分布式锁有临时节点(Ephemeral Node)的效果,也就是说当客户端出问题时,watch在zookeeper的服务会监听到的,  另外由这个客户端建立的键值也会被干掉…  


如果我们用redis来实现分布式锁,是怎么实现? (真想直接贴代码,不废话…)

首先借助于redis的setnx命令来操作,setnx本身针对key赋值的时候会判断redis中是否存在这个key,如果有返回-1,  如果没有的化,他会直接set键值。那他跟直接set键值有啥区别?  setnx是原子操作,而set不能保证原子性。


为了防止锁被长久锁定,或者防止客户端崩掉了没有删掉锁,可以用expire加入过期时间。 但这过期时间也不解决那种客户端异常退出,又没删除锁的情况。  我在使用etcd做服务发现注册时候,用了一个笨办法,把过期时间调的很细,可以开一个线程不停的去设置锁及过期时间.  这样能缓解一般的过期情况.

代码是基于https://github.com/everalbum/redislock/blob/master/redislock.go 修改的,这老外写的代码太高调了。 另外我在这基础上加入了增加过期时间的方法,及自定义prefix key和token,超时时间。

代码我已经整理到 https://github.com/rfyiamcool/go_redis_lock  ,暂不能构建一个可直接用来使用包,没想过要构建一个库包.   下面是实现的代码及test实例…   


这段golang代码运行后的正常结果是:


如果同时起多个进程去测试,会遇到这么一个结果: