Zookeeper实现分布式锁
Zookeeper
介绍zk
zk是一种提供配置管理、分布式协同以及命名的中心化服务
zk的模型:zk包含一系列的节点,叫做znode,就好像文件系统一样每个znode表示一个目录,然后znode有一些特性
- 有序节点:加入当前有一个父节点
/lock
,我们可以在父节点下面创建子节点 zookeeper提供了一个可选的有序特性,例如我们可以创建子节点“/lock/node-”并且指明有序,那么zookeeper在生成子节点时会根据当前的子节点数量自动添加整数序号
也就是说,如果是第一个创建的子节点,那么生成的子节点为/lock/node-0000000000,下一个节点则为/lock/node-0000000001,依次类推。
- 临时节点:客户端可以建立一个临时节点,在会话结束或者会话超时后,zk自动删除该节点
- 事件监听:在读取数据时,我们可以同时对节点设置事件监听,当节点数据或结构变化时,zk会通知客户端
- 节点创建
- 节点删除
- 节点数据修改
- 子节点变更
zk实现分布式锁的落地方案
- 使用zk的临时节点和有序节点,每个线程获取锁就是在zk创建一个临时有序的节点,比如在/lock/目录下。
- 创建节点成功后,获取/lock目录下的所有临时节点,再判断当前线程创建的节点是否是所有的节点的序号最小的节点
- 如果当前线程创建的节点是所有节点序号最小的节点,则认为获取锁成功。
- 如果当前线程创建的节点不是所有节点序号最小的节点,则对节点序号的前一个节点添加一个事件监听。比如当前线程获取到的节点序号为
/lock/003
,然后所有的节点列表为[/lock/001,/lock/002,/lock/003]
,则对/lock/002
这个节点添加一个事件监听器。
如果锁匙放了,会唤醒下一个序号节点,然后重新执行第3步,判断是否自己的节点序号是最小。
比如/lock/001
释放了,/lock/002
监听到事件,此时节点集合为[/lock/002,/lock/003]
,则/lock/002
为最小序号节点,获取到锁。
整个过程如下:
Redis分布式锁与zk锁优缺点对比
Redis:
优点
- 性能高,可以支撑高并发的获取、释放锁操作。
缺点
-
它获取锁的方式简单粗暴,获取不到锁直接不断尝试获取锁,比较消耗性能。
-
另外来说的话,redis的设计定位决定了它的数据并不是强一致性的,在某些极端情况下,可能会出现问题。锁的模型不够健壮
-
即便使用redlock算法来实现,在某些复杂场景下,也无法保证其实现100%没有问题,关于redlock的讨论可以看How to do distributed locking
ZK
优点
-
zookeeper天生设计定位就是分布式协调,强一致性。锁的模型健壮、简单易用、适合做分布式锁。
-
如果获取不到锁,只需要添加一个监听器就可以了,不用一直轮询,性能消耗较小。
缺点
- 如果有较多的客户端频繁的申请加锁、释放锁,对于zk集群的压力会比较大。
Enjoy Reading This Article?
Here are some more articles you might like to read next: