首页
随机
最近更改
特殊页面
社群首页
参数设置
关于WHY42
免责声明
WHY42
搜索
用户菜单
登录
欢迎来到Riguz的小站!这是一个私人wiki,用来记录一些我的笔记。
查看“︁Redis distributed lock”︁的源代码
←
Redis distributed lock
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
Redis一个比较重要的应用场景就是分布式锁DLM (Distributed Lock Manager)。实际上已经有很多现成的redis库来完成这个功能了,但是可能实现途径有所差别,那么,正确的做法是什么呢?Redis官方建议了一个算法叫做`Redlock`,可以将其作为起点去实现更复杂的方案,来研究一下它的思路。 = 原则= 要实现分布式锁得满足一些必要的条件: * 互斥性:任意时刻只能有一个客户端能够成功获取锁 * 避免死锁:即使锁的持有者crash * 容错性:只要redis集群大多数节点正常,客户端就能够获取或者释放锁 有一些常见的做法并不是安全的锁实现方式。 最简单的做法是,获取锁时,在redis创建一个带有过期时间的key。当需要释放锁时,删除这个key。这种做法无法避免单点故障,如果redis master宕机,则无法成功获取或者释放锁了。如果添加一个slave节点呢?很不幸也行不通,因为redis的主从复制是异步的,由此带来竞争: * Client A 在master节点上获取了锁 * master节点在将数据同步到slave之前crash掉了 * slave提升为新的master * Client B于是可以获取到相同的锁了(不满足互斥性) = redis单机下的正确做法= 在不考虑redis集群的情况下,如何正确的实现一个分布式锁呢?其实也比较简单: 加锁: <syntaxhighlight lang="bash"> SET resource_name my_random_value NX PX 30000 </syntaxhighlight> 其中,`NX`保证只有在key不存在的情况下才会被设置到redis中,`PX 30000` 设置了过期时间为30000毫秒。而key的值被设置为一个随机值,这个值必须在所有的客户端和加锁请求中唯一。之所以要这么做,是为了保证能够安全的释放锁,只有当key存在,且是由锁的持有者发起的解锁请求的时候,才删除这个key: <syntaxhighlight lang="lua"> if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end </syntaxhighlight> 主要避免的一个问题就是,锁被其他的客户端给错误地释放了(有可能客户端释放锁的时候,因为某些原因锁已经过期了,但是其他的客户端已经获得了锁)。而锁的过期时间(或者说有效期),应该足够client完成操作,避免任务在进行的过程中其他客户端又获得了锁。 在单机的情况下以上就实现了一个较为完美的锁,如果要扩展到redis集群呢? = Redlock 算法= (TBD) * [https://redis.io/topics/distlock Distributed locks with Redis]
返回
Redis distributed lock
。