ZooKeeper 的数据模型
ZooKeeper的数据模型类似于数据结构中的树
,也很像文件系统
。
ZooKeeper的数据模型基于节点,称为Znode。不同于树的节点的是,Znode的引用方式通过路径
引用,类似于文件系统。数据都存储在内存中。
ZNode分为四种类型:
ZNode的四种类型
- PERSISTENT:持久节点,默认的节点类型。创建节点的客户端与 Zookeeper 断开连接后,该节点依旧存在。
- EPHEMERAL: 临时节点。和持久节点相反,当创建节点的客户端与 Zookeeper 断开连接后,临时节点会被删除。
- PERSISTENT_SEQUENTIAL:持久顺序节点。结合持久节点和顺序节点特性。
- EPHEMERAL_SEQUENTIAL:临时顺序节点。结合临时节点和顺序节点特性。
所谓顺序节点,就是在创建节点时,Zookeeper 根据创建的时间顺序给该节点名称进行编号。
Zookeeper实现分布式锁
Zookeeper 分布式锁是利用临时顺序节点
实现的。
获取锁
首先创建一个持久节点,作为锁的父节点(LockParent)。当有客户端需要获取锁时,在父节点下添加临时顺序节点
。
示意图如下:
之后,客户端查找 LockParent 下面所有的临时顺序节点并排序,判断自己所创建的节点 Lock1 是不是编号最小的一个。如果是,则成功获得锁。
这时,如果再有一个客户端2 来获取锁,则在 LockParent下再创建一个临时顺序节点 Lock2。同样对 LockParent 下面所有的临时顺序节点排序,发现 Lock2 不是编号最小的节点,于是客户端2向排序在它前一个节点
Lock1 注册 Watcher,用于监听 Lock1 节点是否存在。这意味着客户端2获取锁失败,进入了等待状态。
释放锁
释放锁分为两种情况:
操作完成,显示释放
当客户端完成数据的操作后,显示删除自己创建的临时节点。
例如:客户端完成数据操作,显示删除Lock1。此时,由于客户端2对 Lock1 注册了 Watcher ,那么客户端2就会收到 Lock1 节点删除的事件通知,然后客户端2查找 LockParent 下面所有的临时顺序节点并排序,判断自己所创建的节点 Lock2 是不是编号最小的一个。如果是,则成功获得锁。如果不是,则向排序在它前一个节点
注册 Watcher 。
宕机
当客户端操作数据中途宕机了,那么就会断开与 ZooKeeper 服务器的连接,那么根据临时顺序节点的特性,节点会被自动删除。之后的操作就同显示删除一样了。
ZooKeeper 与Redis 分布式锁对比
分布式锁实现 | 优点 | 缺点 |
---|---|---|
ZooKeeper | 1. 有封装好的框架,容易实现 2. 有等待锁的队列,提升获取锁效率 | 添加、删除临时节点效率低 |
Redis | Set和Del执行执行效率高 | 1. 实现复杂,需要考虑原子性、超时、误删等情况 2. 没有等待锁的队列,需要客户端自旋获取锁,效率低 |
注:等待锁的队列是指 LockParent 下的临时节点按照编号排序形成的列表,总是编号小(先创建)的先删除,类似队列FIFO特性。