1、ZAB 协议?
ZAB 协议是为分布式协调服务 Zookeeper 专门设计的一种支持崩溃恢复的原子广播协议。
ZAB 协议包括两种基本的模式:崩溃恢复和消息广播 。
当整个 zookeeper 集群刚刚启动或者 Leader 服务器宕机、重启或者网络故障导致不存在过半的服务器与 Leader 服务器保持正常通信时,所有进程(服务器)进入崩溃恢复模式,首先选举产生新的 Leader 服务器,然后集群中 Follower 服务器开始与新的 Leader 服务器进行数据同步,当集群中超过半数机器与该 Leader服务器完成数据同步之后,退出恢复模式进入消息广播模式,Leader 服务
2、四种类型的数据节点 Znode
1)、PERSISTENT-持久节点
除非手动删除,否则节点一直存在于 Zookeeper 上
2)、EPHEMERAL-临时节点
临时节点的生命周期与客户端会话绑定,一旦客户端会话失效(客户端与zookeeper 连接断开不一定会话失效),那么这个客户端创建的所有临时节点都会被移除。
3)、PERSISTENT_SEQUENTIAL-持久顺序节点
基本特性同持久节点,只是增加了顺序属性,节点名后边会追加一个由父节点维护的自增整型数字。
4)、EPHEMERAL_SEQUENTIAL-临时顺序节点
基本特性同临时节点,增加了顺序属性,节点名后边会追加一个由父节点维护的自增整型数字。
器开始接收客户端的事务请求生成事物提案来进行事务请求处理
3、Zookeeper Watcher 机制 -- 数据变更通知
Zookeeper 允许客户端向服务端的某个 Znode 注册一个 Watcher 监听,当服务端的一些指定事件触发了这个 Watcher,服务端会向指定客户端发送一个事件通知来实现分布式的通知功能,然后客户端根据 Watcher 通知状态和事件类型做出业务上的改变。
工作机制:客户端注册 watcher 服务端处理 watcher 客户端回调 watcher
Watcher 特性总结
1)、一次性
无论是服务端还是客户端,一旦一个 Watcher 被触发,Zookeeper 都会将其从相应的存储中移除。这样的设计有效的减轻了服务端的压力,不然对于更新非常频繁的节点,服务端会不断的向客户端发送事件通知,无论对于网络还是服务端的压力都非常大。
2)、客户端串行执行
客户端 Watcher 回调的过程是一个串行同步的过程。
3)、轻量
Watcher 通知非常简单,只会告诉客户端发生了事件,而不会说明事件的具体内容。
客户端向服务端注册 Watcher 的时候,并不会把客户端真实的 Watcher 对象实体传递到服务端,仅仅是在客户端请求中使用 boolean 类型属性进行了标记。
4、watcher event 异步发送 watcher 的通知事件从 server 发送到 client 是异步的,这就存在一个问题,不同的客户端和服务器之间通过 socket 进行通信,由于网络延迟或其他因素导致客户端在不通的时刻监听到事件,由于 Zookeeper 本身提供了 ordering guarantee,即客户端监听事件后,才会感知它所监视 znode发生了变化。所以我们使用 Zookeeper 不能期望能够监控到节点每次的变化。Zookeeper 只能保证最终的一致性,而无法保证强一致性。
5、注册 watcher getData、exists、getChildren
6、触发 watcher create、delete、setData
7、当一个客户端连接到一个新的服务器上时,watch 将会被以任意会话事件触发。当与一个服务器失去连接的时候,是无法接收到 watch 的。而当 client 重新连接时,如果需要的话,所有先前注册过的 watch,都会被重新注册。通常这是完全透明的。只有在一个特殊情况下,watch 可能会丢失:对于一个未创建的 znode的 exist watch,如果在客户端断开连接期间被创建了,并且随后在客户端连接上之前又删除了,这种情况下,这个 watch 事件可能会被丢失。
8、客户端注册 Watcher 实现
1)、调用 getData()/getChildren()/exist()三个 API,传入 Watcher 对象
2)、标记请求 request,封装 Watcher 到 WatchRegistration
3)、封装成 Packet 对象,发服务端发送 request
4)、收到服务端响应后,将 Watcher 注册到 ZKWatcherManager 中进行管理
5)、请求返回,完成注册。
9、 服务端处理 Watcher 实现
1)、服务端接收 Watcher 并存储
接收到客户端请求,处理请求判断是否需要注册 Watcher,需要的话将数据节点的节点路径和 ServerCnxn(ServerCnxn 代表一个客户端和服务端的连接,实现了 Watcher 的
process 接口,此时可以看成一个 Watcher 对象)存储在WatcherManager 的 WatchTable 和 watch2Paths 中去。
2)、Watcher 触发
以服务端接收到 setData() 事务请求触发 NodeDataChanged 事件为例:
封装 WatchedEvent将通知状态(SyncConnected)、事件类型(NodeDataChanged)以及节点路径封装成一个 WatchedEvent 对象
查询 Watcher从 WatchTable 中根据节点路径查找 Watcher
没找到;说明没有客户端在该数据节点上注册过 Watcher
找到;提取并从 WatchTable 和 Watch2Paths 中删除对应 Watcher(从这里可以看出 Watcher 在服务端是一次性的,触发一次就失效了)
10、Chroot 特性
添加了 Chroot 特性,该特性允许每个客户端为自己设置一个命名空间。
如果一个客户端设置了 Chroot,那么该客户端对服务器的任何操作,都将会被限制在其自己的命名空间下。
11、会话管理
分桶策略:将类似的会话放在同一区块中进行管理,以便于 Zookeeper 对会话进行不同区块的隔离处理以及同一区块的统一处理。
分配原则:每个会话的"下次超时时间点"(ExpirationTime)计算公式:
12、服务器角色
Leader
1)、事务请求的唯一调度和处理者,保证集群事务处理的顺序性
2)、集群内部各服务的调度者
Follower
1)、处理客户端的非事务请求,转发事务请求给 Leader 服务器
2)、参与事务请求 Proposal 的投票
3)、参与 Leader 选举投票
Observer
1)、3.0 版本以后引入的一个服务器角色,在不影响集群事务处理能力的基础上提升集群的非事务处理能力
2)、处理客户端的非事务请求,转发事务请求给 Leader 服务器
3)、不参与任何形式的投票
13、Zookeeper 下 Server 工作状态
服务器具有四种状态,分别是 LOOKING、FOLLOWING、LEADING、OBSERVING。
1)、LOOKING:寻找 Leader 状态。当服务器处于该状态时,它会认为当前集群中没有 Leader,因此需要进入 Leader 选举状态。
2)、FOLLOWING:跟随者状态。表明当前服务器角色是 Follower。
3)、LEADING:领导者状态。表明当前服务器角色是 Leader。
4)、OBSERVING:观察者状态。表明当前服务器角色是 Observer。
14、数据同步
整个集群完成 Leader 选举之后,Learner(Follower 和 Observer 的统称)回向Leader 服务器进行注册。当 Learner 服务器想 Leader 服务器完成注册后,进入数据同步环节。
数据同步流程:(均以消息传递的方式进行)
Learner 向 Learder 注册数据同步同步确认
Zookeeper 的数据同步通常分为四类:
1)、直接差异化同步(DIFF 同步)
2)、先回滚再差异化同步(TRUNC+DIFF 同步)
3)、仅回滚同步(TRUNC 同步)
4)、全量同步(SNAP 同步)
15、zookeeper 是如何保证事务的顺序一致性的?
zookeeper 采用了全局递增的事务 Id 来标识,所有的 proposal(提议)都在被提出的时候加上了 zxid,zxid 实际上是一个 64 位的数字,高 32 位是 epoch(时期; 纪元; 世; 新时代)用来标识 leader 周期,如果有新的 leader 产生出来,epoch会自增,低 32 位用来递增计数。
16、zk 节点宕机如何处理?
Zookeeper 本身也是集群,推荐配置不少于 3 个服务器。Zookeeper 自身也要保证当一个节点宕机时,其他节点会继续提供服务。
如果是一个 Follower 宕机,还有 2 台服务器提供访问,因为 Zookeeper 上的数据是有多个副本的,数据并不会丢失;
如果是一个 Leader 宕机,Zookeeper 会选举出新的 Leader。
ZK 集群的机制是只要超过半数的节点正常,集群就能正常提供服务。只有在 ZK节点挂得太多,只剩一半或不到一半节点能工作,集群才失效。所以3 个节点的 cluster 可以挂掉 1 个节点(leader 可以得到 2 票>1.5)2 个节点的 cluster 就不能挂掉任何 1 个节点了(leader 可以得到 1 票<=1)
17、zookeeper 负载均衡和 nginx 负载均衡区别
zk 的负载均衡是可以调控,nginx 只是能调权重,其他需要可控的都需要自己写插件;但是 nginx 的吞吐量比 zk 大很多,应该说按业务选择用哪种方式。
18、分布式集群中为什么会有 Master?
在分布式环境中,有些业务逻辑只需要集群中的某一台机器进行执行,其他的机器可以共享这个结果,这样可以大大减少重复计算,提高性能,于是就需要进行leader 选举。
19、Zookeeper 有哪几种几种部署模式?
部署模式:单机模式、伪集群模式、集群模式
20、集群最少要几台机器,集群规则是怎样的?
集群规则为 2N+1 台,N>0,即 3 台
21、集群支持动态添加机器吗?
其实就是水平扩容了,Zookeeper 在这方面不太好。两种方式:
全部重启:关闭所有 Zookeeper 服务,修改配置之后启动。不影响之前客户端的会话。
逐个重启:在过半存活即可用的原则下,一台机器重启不影响整个集群对外提供服务。这是比较常用的方式。
22、Zookeeper 对节点的 watch监听通知是永久的吗?为什么不是永久的?
不是。官方声明:一个 Watch 事件是一个一次性的触发器,当被设置了 Watch的数据发生了改变的时候,则服务器将这个改变发送给设置了 Watch 的客户端,以便通知它们。为什么不是永久的,举个例子,如果服务端变动频繁,而监听的客户端很多情况下,每次变动都要通知到所有的客户端,给网络和服务器造成很大压力。一般是客户端执行
getData("/节点 A",true),如果节点 A 发生了变更或删除,客户端会得到它的 watch 事件,但是在之后节点 A 又发生了变更,而客户端又没有设置 watch 事件,就不再给客户端发送。
在实际应用中,很多情况下,我们的客户端不需要知道服务端的每一次变动,我只要最新的数据即可。
23、Zookeeper 的 java 客户端都有哪些?
java 客户端:zk 自带的 zkclient 及 Apache 开源的 Curator。
24、说几个 zookeeper 常用的命令。
常用命令 :ls get set create delete 等。
25、ZAB 和 Paxos 算法的联系与区别?
相同点:
1)、两者 都存 在一 个类似于 Leader进程的角色 ,由其负责 协调 多个 Follower 进程的运 行
2)、Leader进程都会等待超过半数的Follower 做出 正确的反馈后 ,才会将一个提案进行提交
3)、 ZAB 协议中, 每个 Proposal 中都 包含 一个 epoch 值来 代表当前 的 Leader周期 ,Paxos 中名 字为 Ballot
不同点:
ZAB用来构建高可用的分布式数据主备系统( Zookeeper), Paxos是用来构建分布式一致性状态 机系统。
26、Zookeeper 的典型应用场景
Zookeeper 是一个典型的发布/订阅模式的分布式数据管理与协调框架,开发人员可以使用它来进行分布式数据的发布和订阅。
通过对 Zookeeper 中丰富的数据节点进行交叉使用,配合 Watcher 事件通知机制,可以非常方便的构建一系列分布式应用中年都会涉及的核心功能,如:
1)、数据发布/订阅
2)、负载均衡
3)、命名服务
4)、分布式协调/通知
5)、集群管理
6)、Master 选举
27、数据发布/订阅
数据发布/订阅系统,即所谓的配置中心,顾名思义就是发布者发布数据供订阅者进行数据订阅。
目的
动态获取数据(配置信息)
实现数据(配置信息)的集中式管理和数据的动态更新
设计模式 Push 模式 Pull 模式
数据(配置信息)特性
1)、数据量通常比较小
2)、数据内容在运行时会发生动态更新
3)、集群中各机器共享,配置一致
基于 Zookeeper 的实现方式
数据存储:将数据(配置信息)存储到 Zookeeper 上的一个数据节点
数据获取:应用在启动初始化节点从 Zookeeper 数据节点读取数据,并在该节点上注册一个数据变更 Watcher
数据变更:当变更数据时,更新 Zookeeper 对应节点数据,Zookeeper会将数据变更通知发到各客户端,客户端接到通知后重新读取变更后的数据即可。
28、zk 的命名服务
命名服务是指通过指定的名字来获取资源或者服务的地址,利用 zk 创建一个全局的路径,这个路径就可以作为一个名字,指向集群中的集群,提供的服务的地址,或者一个远程的对象
29、分布式通知和协调
对于系统调度来说:操作人员发送通知实际是通过控制台改变某个节点的状态,然后 zk 将这些变化发送给注册了这个节点的 watcher 的所有客户端。
对于执行情况汇报:每个工作进程都在某个目录下创建一个临时节点。并携带工作的进度数据,这样汇总的进程可以监控目录子节点的变化获得工作进度的实时的全局情况。
30、zk 的命名服务(文件系统)
命名服务是指通过指定的名字来获取资源或者服务的地址,利用 zk 创建一个全局的路径,即是唯一的路径,这个路径就可以作为一个名字,指向集群中的集群,提供的服务的地址,或者一个远程的对象等等。
31、zk 的配置管理(文件系统、通知机制)
程序分布式的部署在不同的机器上,将程序的配置信息放在 zk 的 znode 下,当有配置发生改变时,也就是 znode 发生变化时,可以通过改变 zk 中某个目录节点的内容,利用watcher 通知给各个客户端,从而更改配置。
32、Zookeeper 集群管理(文件系统、通知机制)
所谓集群管理无在乎两点:是否有机器退出和加入、选举 master。
对于第一点,所有机器约定在父目录下创建临时目录节点,然后监听父目录节点的子节点变化消息。一旦有机器挂掉,该机器与 zookeeper 的连接断开,其所创建的临时目录节点被删除,所有其他机器都收到通知:某个兄弟目录被删除,于是,所有人都知道:它上船了。新机器加入也是类似,所有机器收到通知:新兄弟目录加入,highcount 又有了,
对于第二点,稍微改变一下,所有机器创建临时顺序编号目录节点,每次选取编号最小的机器作为 master 就好。
33、Zookeeper 分布式锁(文件系统、通知机制**)
有了 zookeeper 的一致性文件系统,锁的问题变得容易。
锁服务可以分为两类,一个是保持独占,另一个是控制时序 对于第一类,我们将 zookeeper 上的一个 znode 看作是一把锁,通过 createznode的方式来实现。所有客户端都去创建 /distribute_lock 节点,最终成功创建的那个客户端也即拥有了这把锁。用完删除掉自己创建的 distribute_lock 节点就释放出锁。
对于第二类, /distribute_lock 已经预先存在,所有客户端在它下面创建临时顺序编号目录节点,和选 master 一样,编号最小的获得锁,用完删除,依次方便。
34、Zookeeper 角色
Zookeeper 集群是一个基于主从复制的高可用集群,每个服务器承担如下三种角色中的一种
Leader
Follower
Observer
35、事务编号 Zxid(事务请求计数器+ epoch)
Zxid 是一个 64 位的数字,其中低 32 位是一个简单的单调递增的计数器, 针对客户端每一个事务请求,计数器加 1;而高 32 位则代表 Leader 周期 epoch 的编号, 每个当选产生一个新的 Leader 服务器,就会从这个 Leader 服务器上取出其本地日志中最大事务的 ZXID,并从中读取epoch 值,然后加 1,以此作为新的 epoch,并将低 32 位从 0 开始计数。
为了保证顺序性,该 zkid 必须单调递增
36、epoch
epoch:可以理解为当前集群所处的年代或者周期,每个 leader 就像皇帝,都有自己的年号,所以每次改朝换代, leader 变更之后,都会在前一个年代的基础上加 1。
这样就算旧的 leader 崩溃恢复之后,也没有人听他的了,因为 follower 只听从当前年代的 leader 的命令。
37、Zab 协议有两种模式-恢复模式(选主)、广播模式(同步)
Zab 协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步) 。当服务启动或者在领导者崩溃后, Zab 就进入了恢复模式,当领导者被选举出来,且大多数 Server完成了和 leader 的状态同步以后,恢复模式就结束了。状态同步保证了 leader 和 Server 具有相同的系统状态
38、Leader election(选举阶段-选出准 Leader)
Leader election(选举阶段) : 节点在一开始都处于选举阶段,只要有一个节点得到超半数节点的票数,它就可以当选准 leader。
只有到达广播阶段(broadcast) 准 leader才会成为真正的 leader。
39、Discovery(发现阶段-接受提议、生成 epoch、接受 epoch)
Discovery(发现阶段) : 在这个阶段, followers 跟准 leader 进行通信,同步 followers最近接收的事务提议。这个一阶段的主要目的是发现当前大多数节点接收的最新提议,并且准 leader 生成新的 epoch,让 followers 接受更新它们的 accepted Epoch一个 follower 只会连接一个 leader, 如果有一个节点 f 认为另一个 followerp 是 leader, f在尝试连接p时会被拒绝, f 被拒绝之后,就会进入重新选举阶段
40、Synchronization(同步阶段-同步 follower 副本)
Synchronization(同步阶段) : 同步阶段主要是利用 leader 前一阶段获得的最新提议历史,同步集群中所有的副本。 只有当 大多数节点都同步完成,准 leader 才会成为真正的 leader。follower 只会接收 zxid 比自己的 lastZxid 大的提议
41、Broadcast(广播阶段-leader 消息广播)
Broadcast(广播阶段) : 到了这个阶段, Zookeeper 集群才能正式对外提供事务服务,并且 leader 可以进行消息广播。同时如果有新的节点加入,还需要对新节点进行同步
42、投票机制
每个 sever 首先给自己投票, 然后用自己的选票和其他 sever 选票对比, 权重大的胜出,使用权重较大的更新自身选票箱。
43、Zookeeper 工作原理(原子广播)
Zookeeper 的核心是原子广播,这个机制保证了各个 server 之间的同步。实现这个机制的协议叫做 Zab 协议。
44、Znode 有四种形式的目录节点
PERSISTENT:持久的节点。
EPHEMERAL: 暂时的节点。
PERSISTENT_SEQUENTIAL:持久化顺序编号目录节点。
EPHEMERAL_SEQUENTIAL:暂时化顺序编号目录节点。
45、栈(stack)
后进先出(LIFO)的。
对栈的基本操作只有 push(进栈)和 pop(出栈)两种,
进栈相当于插入,出栈相当于删除最后的元素。
46、队列(queue)
队列是一种特殊的线性表
只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作
插入操作的端称为队尾,进行删除操作的端称为队头。
47、链表(Link)
链表是一种数据结构,和数组同级
ArrayList,其实现原理是数组
LinkedList 的实现原理就是链表
链表在进行循环遍历时效率不高,但是插入和删除时优势明显
48、散列表(Hash Table)
哈希表是一种查找算法
散列表算法希望能尽量做到不经过任何比较,通过一次存取就能得到所查找的数据元素,因而必须要在数据元素的存储位置和它的关键字(可用 key 表示)之间建立一个确定的对应关系,使每个关键字和散列表中一个唯一的存储位置相对应
查找时,只要根据这个对应关系找到给定关键字在散列表中的位置即可
对应关系被称为散列函数
构造散列函数的方法有:
直接定址法
取关键字或关键字的某个线性函数值为散列地址。
平方取值法: 取关键字平方后的中间几位为散列地址。
折叠法: 将关键字分割成位数相同的几部分,然后取这几部分的叠加和作为散列地址。
除留余数法: 取关键字被某个不大于散列表表长 m 的数 p 除后所得的余数为散列地址
随机数法: 选择一个随机函数,取关键字的随机函数值为它的散列地址
49、排序二叉树
首先如果普通二叉树每个节点满足:左子树所有节点值小于它的根节点值,且右子树所有节点值大于它的根节点值,则这样的二叉树就是排序二叉树。
插入操作
从根节点开始往下找到自己要插入的位置(即新节点的父节点)
新节点与当前节点比较,如果相同则表示已经存在且不能再重复插入
如果小于当前节点,则到左子树中寻找,如果左子树为空则当前节点为要找的父节点,新节点插入到当前节点的左子树即可;
如果大于当前节点,则到右子树中寻找,如果右子树为空则当前节点为要找的父节点,新节点插入到当前节点的右子树即可。
删除操作
删除操作分为三种情况
对于要删除的节点无子节点可以直接删除,即让其父节点将该子节点置空即可。
对于要删除的节点只有一个子节点,则替换要删除的节点为其子节点。
对于要删除的节点有两个子节点, 则首先找该节点的替换节点(即右子树中最小的节点),接着替换要删除的节点为替换节点,然后删除替换节点。
查询操作
查找操作的主要流程为:先和根节点比较,如果相同就返回, 如果小于根节点则到左子树中归查找,如果大于根节点则到右子树中递归查找。
排序二叉树中可以很容易获取最大(最右最深子节点)和最小(最左最深子节点)值
50、 前缀树
前缀树与树类似用于处理字符串相关的问题时非常高效
可以实现快速检索,常用于字典中的单词查询,搜索引擎的自动补全甚至 IP 路由