ZooKeeper介绍:
ZooKeeper是一个分布式协调服务,用于服务治理.
提供了文件系统,通知机制,分布式应用程序可以基于Zookeeper实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master选举、分布式锁和分布式队列等功能。为分布式系统解决数据同步问题,任务执行顺序问题,master选举问题,事务一致性问题。
ZooKeeper的设计思想:
防止单点故障:采用高可用和高性能(分摊流量)的集群方案。
要实现高可用必须保证每个节点数据的一致性:
要实现各个节点的数据一致性,就势必要一个leader节点负责协调和数据同步操作。
如何举出 leader 节点,leader节点宕机如何恢复数据:
采用ZAB协议
如何保证分布式事务一致性(ACID):
解决分布式事务的数据一致性协议有2PC协议和3PC协议。
ZooKeeper集群角色:
Leader角色:
负责协调和数据同步操作.
1.事务请求的唯一调度和处理者,保证集群事物处理的顺序性
2.集群内部各服务器的调度者
Follower角色:
1.处理客户端非事物请求、转发事物请求给leader服务器
2.参与事务请求提议(proposal)投票
3.参与leader投票
Observer角色:
类似Follower角色,处理客户端非事物请求、转发事物请求给leader服务器
单不参与任何形式投票
集群组成:
集群规则为2N+1台,N>0,即3台。
zookeeper是如何保证事务的顺序一致性的?
当处理事务请求时,会先成一个事务ID(ZXID)如图,同一个Leader的统治下epoch(leader周期)是相同的,counter消息计数器随着事务的增加而递增,会按照请求顺序转发给Leader,并保存在一个FIFO队列中,这样就可以保证事务的顺序一致性。然后
1.事务请求发送到follower服务器节点(若发送给Leader节点少了转发这一步)
2.首先会把事务请求转发给leader,
3.leader 服务器把客户端的失去请求转化成一个事务 Proposal(提议),并把这个 Proposal 分发给集群中的所有 Follower 服务器,
4.如果过半的follower节点同意(返回ACK)
5.Leader 就会再次向所有的Follower 服务器发送 Commit 消息,要求各个 follower 节点对前面的一个 Proposal 进行提交;
6.把最后的结果同步给Observer节点,
7.把结果返回给客户端。
ZAB协议?
ZAB协议是为分布式协调服务Zookeeper专门设计的一种支持崩溃恢复的原子广播协议。
ZAB协议包括两种基本的模式:崩溃恢复和消息广播。
消息广播存在事务处理实现原理:
1. Leader 接收到消息请求后,将消息赋予一个全局唯一的64 位自增 id,叫:zxid,通过 zxid 的大小比较实现顺序特征;
2. Leader 为每个 follower 准备了一个 FIFO 队列(通过 TCP协议来实现,以实现了全局有序这一个特点)将带有 zxid的消息作为一个提案(proposal)分发给所有的 follower;
3.当 follower 接收到 proposal,先把 proposal 写到磁盘,写入成功以后再向 leader 回复一个 ack
4.当 leader 接收到合法数量(超过半数节点)的 ACK 后,leader 就会向这些 follower 发送 commit 命令,同时会在本地执行该消息
5.当 follower 收到消息的 commit 命令以后,会提交该消息
崩溃恢复(数据恢复)原理:
由于Leader节点崩溃或者由于网络问题导致Leader 服务器失去了过半的 Follower 节点的联系那么就会进入到崩溃恢复模式。重新选取leader
已经被处理的消息不能丢失
leader发送commit消息给follower-A但发送给follower-B的时候挂了。zab协议下需要保证所有机器都要执行这个事务消息
被丢弃的消息不能再次出现
当提议生成但未发送到follower时挂了,重新选举后,原leader保留这个提议,与整个系统状态不一样需要删除这个提议。
Leaderr选举:
Leader 选举会分两个过程:
启动的时候的leader选举
leader 崩溃的时候的的选举
服务器启动时的 leader 选举
每个节点启动的时候状态都是 LOOKING,处于观望状态,接下来就开始进行选主流程
进行 Leader 选举,至少需要两台机器(具体原因前面已经讲过了),我们选取 3 台机器组成的服务器集群为例。在集群初始化阶段,当有一台服务器 Server1 启动时,它本身是无法进行和完成 Leader 选举,当第二台服务器 Server2 启动时,这个时候两台机器可以相互通信,每台机器都试图找到 Leader,于是进入 Leader 选举过程。选举过程如下:
(1) 每个 Server 发出一个投票。由于是初始情况,Server1和 Server2 都会将自己作为 Leader 服务器来进行投票,每次投票会包含所推举的服务器的 myid 和 ZXID、epoch,使用(myid, ZXID,epoch)来表示,此时 Server1的投票为(1, 0),Server2 的投票为(2, 0),然后各自将这个投票发给集群中其他机器。
(2)接受来自各个服务器的投票。集群的每个服务器收到投票后,首先判断该投票的有效性,如检查是否是本轮投票(epoch)、是否来自LOOKING状态的服务器。
(3) 处理投票。针对每一个投票,服务器都需要将别人的投票和自己的投票进行 PK,PK 规则如下
i.优先检查 ZXID。ZXID 比较大的服务器优先作为Leader
如果 leader 选举算法能够保证新选举出来的 Leader 服务器拥有集群中所有机器最高编号(ZXID 最大)的事务Proposal,那么就可以保证这个新选举出来的 Leader 一定具有已经提交的提案。因为所有提案被 COMMIT 之前必须有超过半数的 follower ACK,即必须有超过半数节点的服务器的事务日志上有该提案的 proposal,因此,只要有合法数量的节点正常工作,就必然有一个节点保存了所有被 COMMIT 消息的 proposal 状态
ii. 如果 ZXID 相同,那么就比较 myid。myid 较大的服务器作为 Leader 服务器。
对于 Server1 而言,它的投票是(1, 0),接收 Server2的投票为(2, 0),首先会比较两者的 ZXID,均为 0,再比较 myid,此时 Server2 的 myid 最大,于是更新自己的投票为(2, 0),然后重新投票,对于 Server2 而言,它不需要更新自己的投票,只是再次向集群中所有机器发出上一次投票信息即可。
(4) 统计投票。每次投票后,服务器都会统计投票信息,判断是否已经有过半机器接受到相同的投票信息,对于 Server1、Server2 而言,都统计出集群中已经有两台机器接受了(2, 0)的投票信息,此时便认为已经选出了 Leader。
(5) 改变服务器状态。一旦确定了 Leader,每个服务器就会更新自己的状态,如果是 Follower,那么就变更为FOLLOWING,如果是 Leader,就变更为 LEADING。
运行过程中的 leader 选举
当集群中的 leader 服务器出现宕机或者不可用的情况时,那么整个集群将无法对外提供服务,而是进入新一轮的Leader 选举,服务器运行期间的 Leader 选举和启动时期的 Leader 选举基本过程是一致的。
(1) 变更状态。Leader 挂后,余下的非 Observer 服务器都会将自己的服务器状态变更为 LOOKING,然后开始进入 Leader 选举过程。
(2) 每个 Server 会发出一个投票。在运行期间,每个服务器上的 ZXID 可能不同,此时假定 Server1 的 ZXID 为123,Server3的ZXID为122;在第一轮投票中,Server1和 Server3 都会投自己,产生投票(1, 123),(3, 122),然后各自将投票发送给集群中所有机器。接收来自各个服务器的投票。与启动时过程相同。
(3) 处理投票。与启动时过程相同,此时,Server1 将会成为 Leader。
(4) 统计投票。与启动时过程相同。
(5) 改变服务器的状态。与启动时过程相同
分布式锁:
基于ZooKeeper的临时有序节点和watch机制。当要获取锁时在某个目录下创建一个临时有序节点,每次创建均能成功,只是返回的节点序号不同。只有返回的节点序号是该目录下最小的才表示获取锁成功,否则表示获取锁失败,此时watch监控节点序号比本身小的前一个节点,当watch的节点被删除后再去尝试获取锁。
优缺点:
1.Redis分布式锁需要轮询获取锁,性能开销较大。ZooKeeper分布式锁基于watch机制监听节点,不需要轮询获取锁,性能开销较小。
2.如果Redis获取锁的客户端非正常退出,那么只能等待超时时间之后才能释放锁。Redis因为创建的是临时节点,只要客户端崩溃或者连接断开,临时节点就会被删除,锁也就被立即释放了。
PS:zookeeper面试题参考
分布式锁demo