Golang使用redigo实现redis的分布式锁
rfyiamcool · · 7628 次点击 · · 开始浏览有些分布式场景会有分布式锁的需求,可以为了原子操作,也可能为了性能的原因,不管是分布式锁市面是有不少解决方法的,比如etcd、consul、zookeeper... 初次之外redis这样的nosql也是可以实现分布式锁的。 python党喜欢用redis、etcd、consul来搞。 java这帮人更喜欢用zookeeper来实现分布式锁,zookeeper做分布式锁有临时节点(Ephemeral Node)的效果,也就是说当客户端出问题时,watch在zookeeper的服务会监听到的, 另外由这个客户端建立的键值也会被干掉...
该文章写的有些乱,欢迎来喷 ! 另外文章后续不断更新中,请到原文地址查看更新http://xiaorui.cc/?p=3028
如果我们用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代码运行后的正常结果是:
如果同时起多个进程去测试,会遇到这么一个结果:
有疑问加站长微信联系(非本文作者)
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
关注微信- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码` - 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传
收入到我管理的专栏 新建专栏
有些分布式场景会有分布式锁的需求,可以为了原子操作,也可能为了性能的原因,不管是分布式锁市面是有不少解决方法的,比如etcd、consul、zookeeper... 初次之外redis这样的nosql也是可以实现分布式锁的。 python党喜欢用redis、etcd、consul来搞。 java这帮人更喜欢用zookeeper来实现分布式锁,zookeeper做分布式锁有临时节点(Ephemeral Node)的效果,也就是说当客户端出问题时,watch在zookeeper的服务会监听到的, 另外由这个客户端建立的键值也会被干掉...
该文章写的有些乱,欢迎来喷 ! 另外文章后续不断更新中,请到原文地址查看更新http://xiaorui.cc/?p=3028
如果我们用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代码运行后的正常结果是:
如果同时起多个进程去测试,会遇到这么一个结果: