Znode
结构:
- path:唯一路径
- childNode:子节点
- stat:状态属性
- type:节点类型
节点类型:
类型 | 描述 |
---|---|
PERSISTENT | 持久节点(默认节点) |
PERSISTENT_SEQUENTIAL | 持久序号节点 |
EPHEMERAL | 临时节点(不可再拥有子节点) |
EPHEMERAL_SEQUENTIAL | 临时序号节点(不可再拥有子节点) |
不过看了源码后发现不止这些.
ZK集群
集群角色:
- leader : 主节点,写节点.选举产生
- follower : 从节点,读节点.
- observer : 读节点,没有投票权,用于缓解集群的读压力,但同时又不增加选举的复杂度(像不像外包?)
集群选举:
-
触发条件 :
- 服务节点初始化启动
- 半数以上节点无法和leader建立连接
-
投票规则 : 第一轮投票全部投给自己 第二轮投票给myid比自己大的相邻节点
-
选举完成条件 : 当某节点得票超过半数,则其当选leader,选举结束
Watcher 事件监听器
- ZooKeeper 允许用户在指定节点上注册一些 Watcher,并且在一些特定事件触发的时候,ZooKeeper 服务端会将事件通知到感兴趣的客户端上去,该机制是 ZooKeeper 实现分布式协调服务的重要特性
崩溃恢复
- 当leader出现异常或者网络异常,导致过半的节点无法与leader取得联系,那么集群会进入崩溃恢复阶段,重新选举出新的leader
- 选出新leader后,新leader要完成整个集群的同步工作,也就是保证过半的节点能够和leader保持数据状态一致
消息广播
- 当集群数据同步完成后,才进入消息广播阶段,才能对外开放服务
zk写数据过程
- 用户找到其中一个follower/observer,它会将写请求转发给leader
- leader会为这个请求生成一个全局唯一的zxid(事务编号),然后向全体follower发起投票来决定接不接受这个写请求
- 如果follower收到的写请求的zxid大于本地记录的最大zxid,那么就会向leader回复一个ack
- 如果同意过半,那么leader会向全体follower发起无条件写请求,follower执行之后会更新本地记录中的zxid
- 考虑一种情况,如果leader向follower发送一个请求A,但是它丢失了,之后leader又发送了一个请求B,此时follower的ack实际是回复请求A的,但leader可能会误会成同意执行请求A.为了解决这种问题,zk的做法是为每个follower维护一个滑动窗口,全为唯一的zxid作为窗口编号,只接收按序到达的ack.
分布式锁
- 首先肯定是如何获取锁,因为创建节点的唯一性,我们可以让多个客户端同时创建一个临时节点,创建成功的就说明获取到了锁 。然后没有获取到锁的客户端也像上面选主的非主节点创建一个
watcher
进行节点状态的监听,如果这个互斥锁被释放了(可能获取锁的客户端宕机了,或者那个客户端主动释放了锁)可以调用回调函数重新获得锁。 zk
中不需要向redis
那样考虑锁得不到释放的问题了,因为当客户端挂了,节点也挂了,锁也释放了