ZooKeeper的工作原理

在zookeeper的集群中,各个节点共有下面3种角色和4种状态:

  • 角色:leader,follower,observer
  • 状态:leading,following,observing,looking

Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议(ZooKeeper Atomic Broadcast protocol)。Zab协议有两种模式,它们分别是恢复模式(Recovery选主)和广播模式(Broadcast同步)。

当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和leader的状态同步以后,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。

为了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。所有的提议(proposal)都在被提出的时候加上了zxid。

实现中zxid是一个64位的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的统治时期。低32位用于递增计数。

Leader Election

当leader崩溃或者leader失去大多数的follower,这时候zk进入恢复模式,恢复模式需要重新选举出一个新的leader,让所有的Server都恢复到一个正确的状态。Zk的选举算法有两种:一种是基于basic paxos实现的,另外一种是基于fast paxos算法实现的。系统默认的选举算法为fast paxos。先介绍basic paxos流程:

  1. 选举线程由当前Server发起选举的线程担任,其主要功能是对投票结果进行统计,并选出推荐的Server;
  2. 选举线程首先向所有Server发起一次询问(包括自己);
  3. 选举线程收到回复后,验证是否是自己发起的询问(验证zxid是否一致),然后获取对方的id(myid),并存储到当前询问对象列表中,最后获取对方提议的leader相关信息(id,zxid),并将这些信息存储到当次选举的投票记录表中;
  4. 收到所有Server回复以后,就计算出zxid最大的那个Server,并将这个Server相关信息设置成下一次要投票的Server;
  5. 线程将当前zxid最大的Server设置为当前Server要推荐的Leader,如果此时获胜的Server获得n/2 + 1的Server票数,设置当前推荐的leader为获胜的Server,将根据获胜的Server相关信息设置自己的状态,否则,继续这个过程,直到leader被选举出来。

通过流程分析我们可以得出:要使Leader获得多数Server的支持,则Server总数必须是奇数2n+1,且存活的Server的数目不得少于n+1.

每个Server启动后都会重复以上流程。在恢复模式下,如果是刚从崩溃状态恢复的或者刚启动的server还会从磁盘快照中恢复数据和会话信息,zk会记录事务日志并定期进行快照,方便在恢复时进行状态恢复。

fast paxos流程是在选举过程中,某Server首先向所有Server提议自己要成为leader,当其它Server收到提议以后,解决epoch和zxid的冲突,并接受对方的提议,然后向对方发送接受提议完成的消息,重复这个流程,最后一定能选举出Leader。

Leader工作流程

Leader主要有三个功能:

  1. 恢复数据;
  2. 维持与follower的心跳,接收follower请求并判断follower的请求消息类型;
  3. follower的消息类型主要有PING消息、REQUEST消息、ACK消息、REVALIDATE消息,根据不同的消息类型,进行不同的处理。

说明:

PING消息是指follower的心跳信息;REQUEST消息是follower发送的提议信息,包括写请求及同步请求;
ACK消息是follower的对提议的回复,超过半数的follower通过,则commit该提议;
REVALIDATE消息是用来延长SESSION有效时间。

Follower工作流程

Follower主要有四个功能:

  1. 向Leader发送请求(PING消息、REQUEST消息、ACK消息、REVALIDATE消息);
  2. 接收Leader消息并进行处理;
  3. 接收Client的请求,如果为写请求,发送给Leader进行投票;
  4. 返回Client结果。

Follower的消息循环处理如下几种来自Leader的消息:

  1. PING消息:心跳消息
  2. PROPOSAL消息:Leader发起的提案,要求Follower投票
  3. COMMIT消息:服务器端最新一次提案的信息
  4. UPTODATE消息:表明同步完成
  5. REVALIDATE消息:根据Leader的REVALIDATE结果,关闭待revalidate的session还是允许其接受消息
  6. SYNC消息:返回SYNC结果到客户端,这个消息最初由客户端发起,用来强制得到最新的更新。

Zab: Broadcasting State Updates

Zookeeper Server接收到一次request,如果是follower,会转发给leader,Leader执行请求并通过Transaction的形式广播这次执行。Zookeeper集群如何决定一个Transaction是否被commit执行?通过“两段提交协议”(a two-phase commit):

  • Leader给所有的follower发送一个PROPOSAL消息。
  • 一个follower接收到这次PROPOSAL消息,写到磁盘,发送给leader一个ACK消息,告知已经收到。
  • 当Leader收到法定人数(quorum)的follower的ACK时候,发送commit消息执行。

Zab协议保证:

  • 如果leader以T1和T2的顺序广播,那么所有的Server必须先执行T1,再执行T2。
  • 如果任意一个Server以T1、T2的顺序commit执行,其他所有的Server也必须以T1、T2的顺序执行。

“两段提交协议”最大的问题是如果Leader发送了PROPOSAL消息后crash或暂时失去连接,会导致整个集群处在一种不确定的状态(follower不知道该放弃这次提交还是执行提交)。Zookeeper这时会选出新的leader,请求处理也会移到新的leader上,不同的leader由不同的epoch标识。切换Leader时,需要解决下面两个问题:

1. Never forget delivered messages

Leader在COMMIT投递到任何一台follower之前crash,只有它自己commit了。新Leader必须保证这个事务也必须commit。

2. Let go of messages that are skipped

Leader产生某个proposal,但是在crash之前,没有follower看到这个proposal。该server恢复时,必须丢弃这个proposal。

Zookeeper会尽量保证不会同时有2个活动的Leader,因为2个不同的Leader会导致集群处在一种不一致的状态,所以Zab协议同时保证:

  • 在新的leader广播Transaction之前,先前Leader commit的Transaction都会先执行。
  • 在任意时刻,都不会有2个Server同时有法定人数(quorum)的支持者。
    这里的quorum是一半以上的Server数目,确切的说是有投票权力的Server(不包括Observer)。

Zookeeper集群角色

Leader
事务请求的唯一调度和处理者,保证集群事务处理的顺序性
集群内部各服务的调度者

Follower
处理客户端的非事务请求,转发事务请求给Leader服务器
参与事务请求Proposal的投票
参与Leader选举投票
Observer
3.3.0版本以后引入的一个服务器角色,在不影响集群事务处理能力的基础上提升集群的非事务处理能力
处理客户端的非事务请求,转发事务请求给Leader服务器
不参与任何形式的投票

Zookeeper 下 Server工作状态

  • LOOKING:当前Server不知道leader是谁,正在搜寻。 寻 找 Leader 状态。当服务器处于该状态时,它会认为当前集群中没有 Leader,因此需要进入 Leader 选举状态。
  • LEADING:当前Server即为选举出来的leader。领导者状态。表明当前服务器角色是 Leader。
  • FOLLOWING:leader已经选举出来,当前Server与之同步。跟随者状态。表明当前服务器角色是 Follower。
  • OBSERVING:observer的行为在大多数情况下与follower完全一致,但是他们不参加选举和投票,而仅仅接受(observing)选举和投票的结果。 观察者状态。表明当前服务器角色是 Observer。

    zookeeper的observer节点是用来干什么的


    observer节点不参与leader选举,只是单纯的接收数据同步数据,可能数据存在一定不一致的问题,但是observer是只读的. 也就是说observer提供读请求的处理.
    一个zookeeper集群不要添加太多的follower,一般有三四个follower就差不多了,因为leader在写请求的时候,要过半的follower发送ack才行,这样会增加网络压力等等.
    如果你为了增加zookeeper集群的qps而添加过多的follower的话,势必会造成网络压力,而给zookeeper机器添加observer的话 这样的话就能提高zookeeper集群的 qps.哪怕你添加20多个observer机器也不会影响zookeeper的写入性能.

Zookeeper 怎么保证主从节点的状态同步?

Zookeeper 的核心是原子广播机制,这个机制保证了各个 server 之间的同步。实现这个机制的协议叫做 Zab 协议。Zab 协议有两种模式,它们分别是恢复模式和广播模式。

1.恢复模式

当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数 server 完成了和 leader 的状态同步以后,恢复模式就结束了。状态同步保证了 leader 和 server 具有相同的系统状态。

2.领导选举的流程

Zookeeper集群相关概念 - 图1
l 每个Server会发出一个投票,第一次都是投自己。投票信息:(myid,ZXID)
l 收集来自各个服务器的投票
l 处理投票并重新投票,处理逻辑:优先比较ZXID,然后比较myid
l 统计投票,只要超过半数的机器接收到同样的投票信息,就可以确定leader
l 改变服务器状态

3.消息广播的流程

Zookeeper集群相关概念 - 图2
Leader 接收到消息请求后,将消息赋予一个全局唯一的 64 位自增 id,叫做:zxid,通过 zxid 的大小比较即可实现因果有序这一特性。
Leader 通过先进先出队列(通过 TCP 协议来实现,以此实现了全局有序这一特性)将带有 zxid 的消息作为一个提案(proposal)分发给所有 follower。
当 follower 接收到 proposal,先将 proposal 写到硬盘,写硬盘成功后再向 leader 回一个 ACK。
当 leader 接收到合法数量的 ACKs 后,leader 就向所有 follower 发送 COMMIT 命令,会在本地执行该消息。
当 follower 收到消息的 COMMIT 命令时,就会执行该消息

zookeeper保证CP


在此ZooKeeper保证的是CP

分析:可用性(A:Available)

不能保证每次服务请求的可用性。任何时刻对ZooKeeper的访问请求能得到一致的数据结果,同时系统对网络分割具备容错性;但是它不能保证每次服务请求的可用性(注:也就是在极端环境下,ZooKeeper可能会丢弃一些请求,消费者程序需要重新请求才能获得结果)。所以说,ZooKeeper不能保证服务可用性。

进行leader选举时集群都是不可用。在使用ZooKeeper获取服务列表时,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30 ~ 120s, 且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪,虽然服务能够最终恢复,但是漫长的选举时间导致的注册长期不可用是不能容忍的。所以说,ZooKeeper不能保证服务可用性。

zookeeper 是如何保证事务的顺序一致性的


zookeeper 采用了全局递增的事务 Id 来标识,所有的 proposal(提议)都在被提出的时候加上了 zxid,zxid 实际上是一个 64 位的数字,高 32 位是 epoch用来标识 leader 周期,如果有新的 leader 产生出来,epoch会自增,低 32 位用来递增计数。当新产生 proposal 的时候,会依据数据库的两阶段过程,首先会向其他的 server 发出事务执行请求,如果超过半数的机器都能执行并且能够成功,那么就会开始执行。

分布式集群中为什么会有 Master主节点?

在分布式环境中,有些业务逻辑只需要集群中的某一台机器进行执行,其他的机器可以共享这个结果,这样可以大大减少重复计算,提高性能,于是就需要进行 leader 选举。

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)

Zookeeper 有哪几种几种部署模式

Zookeeper 有三种部署模式:

1. 单机部署:一台集群上运行;
2. 集群部署:多台集群运行;
3. 伪集群部署:一台集群启动多个 Zookeeper 实例运行。

集群最少要几台机器,集群规则是怎样的?集群中有 3 台服务器,其中一个节点宕机,这个时候 Zookeeper 还可以使用吗?

集群规则为 2N+1 台,N>0,即 3 台。可以继续使用,单数服务器只要没超过一半的服务器宕机就可以继续使用。

集群支持动态添加机器吗?

其实就是水平扩容了,Zookeeper 在这方面不太好。两种方式:

全部重启:关闭所有 Zookeeper 服务,修改配置之后启动。不影响之前客户端的会话。

逐个重启:在过半存活即可用的原则下,一台机器重启不影响整个集群对外提供服务。这是比较常用的方式。

3.5 版本开始支持动态扩容。

为了满足分布式系统的需求,ZooKeeper的架构设计有哪些特点?

集群化部署
3~5台机器组成一个机器,每台机器都在内存保存了zookeeper的全部的数据,机器之间互相通信同步数据,客户端连接任何一台服务器都可以.

树形结构的数据模型
znode节点,类似于文件系统,数据模型简单,纯内存存储.

写的时候是顺序写
zookeeper集群中只有一台机器可以接收写请求,但是所有的机器都可以接收读请求.
写的时候只能从leader节点去写,并且给你分配一个全局唯一递增的id(zxid)来保证顺序性.
这样保证各种客户端往zookeeper集群发起的写请求都是顺序性的,

数据一致性
只有leader能处理写请求,如果其它角色机器接收到写请求会转发给leader,

高性能
每台zookeeper都是在内存中维护数据的, 所以zookeeper集群绝对是高并发高性能的,如果你让zookeeper部署在一个高配置的物理机上,一个3台机器的zookeeper集群能抗下每秒几万请求没问题.

高可用
哪怕集群中挂掉的机器数量不超过一半儿的机器,都能保证zookeeper集群的可用,数据也不会丢失.
3台机器的zookeeper集群最多只能挂1台机器
5台机器的zookeeper集群最多只能挂2台机器

分布式集群中为什么会有 Master主节点?

在分布式环境中,有些业务逻辑只需要集群中的某一台机器进行执行,其他的机器可以共享这个结果,这样可以大大减少重复计算,提高性能,于是就需要进行 leader 选举。

Zookeeper 怎么保证主从节点的状态同步?

Zookeeper 的核心是原子广播机制,这个机制保证了各个 server 之间的同步。实现这个机制的协议叫做 Zab 协议。Zab 协议有两种模式,它们分别是恢复模式和广播模式。

1. 恢复模式

当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数 server 完成了和 leader 的状态同步以后,恢复模式就结束了。状态同步保证了 leader 和 server 具有相同的系统状态。

2. 广播模式

一旦 leader 已经和多数的 follower 进行了状态同步后,它就可以开始广播消息了,即进入广播状态。这时候当一个 server 加入 ZooKeeper 服务中,它会在恢复模式下启动,发现 leader,并和 leader 进行状态同步。待到同步结束,它也参与消息广播。ZooKeeper 服务一直维持在 Broadcast 状态,直到 leader 崩溃了或者 leader 失去了大部分的 followers 支持。

zookeeper 是如何保证事务的顺序一致性的?

zookeeper 采用了全局递增的事务 Id 来标识,所有的 proposal(提议)都在被提出的时候加上了 zxid,zxid 实际上是一个 64 位的数字,高 32 位是 epoch( 时期; 纪元; 世; 新时代)用来标识 leader 周期,如果有新的 leader 产生出来,epoch会自增,低 32 位用来递增计数。当新产生 proposal 的时候,会依据数据库的两阶段过程,首先会向其他的 server 发出事务执行请求,如果超过半数的机器都能执行并且能够成功,那么就会开始执行。

Zookeeper节点宕机如何处理?

Zookeeper本身也是集群,推荐配置不少于3个服务器。Zookeeper自身也要保证当一个节点宕机时,其他节点会继续提供服务。
如果是一个Follower宕机,还有2台服务器提供访问,因为Zookeeper上的数据是有多个副本的,数据并不会丢失;
如果是一个Leader宕机,Zookeeper会选举出新的Leader。

ZK集群的机制是只要超过半数的节点正常,集群就能正常提供服务。
只有在ZK节点挂得太多,只剩一半或不到一半节点能工作,集群才失效。

所以:

· 3个节点的cluster可以挂掉1个节点(leader可以得到2票>1.5)
· 2个节点的cluster不能挂掉任何1个节点(leader可以得到1票<=1)

奔溃恢复时选举出来的leader是如何跟其它的follower进行同步的?

假如说有5台机器,leader宕机之后,剩下4个follower会选出一个收到事务zxid里面最大的那个follower作为新的leader.
事务zxid最大的机器里面的数据肯定是成最完整最新的,此时这个新的leader就会给自己的数据同步给其它的follower.

Zookeeper的集群刚启动起来和平稳运行的时候的Leader选举

Leader选举算法和流程


每个ZooKeeper都有两个Id,一个是代表自己的Pid,一个是代表本身所存储的数据的Zid,
一开始还没有leader也没有数据的时候会选举最大的Pid当leader
当运行突然崩溃时,先每个都选举自己,广播自己的Pid和Zid,然后收到的机器广播最大的那个Zid对应的Pid,当半数+1ZooKeeper同意的时候即成为Leader

Zookeeper选举机制,会不会脑裂

假如A客户端网络有点问题,但是Zookeeper以为A客户端死掉了,就给Zookeeper里面的A用分布式锁的临时顺序节点给删了,其实A客户端还在基于获取到分布式锁的情况下执行了很多代码.

此时B客户端因为Zookeeper给A临时节点删除了,那么B客户端收到了watcher通知就认为自己加锁成功了,客户端B就会基于加锁的状态运行很多代码.这个时候就出现问题了.

如何解决脑裂的:
选举过半机制
https://www.yuque.com/docs/share/985f07ac-40fe-4fba-84c1-739e4b44aa8a?# 《Zookeeper是如何解决脑裂的》
https://www.yuque.com/docs/share/0a0147ea-e3b1-45d6-a9a0-31b05181fe7d?# 《Zookeeper脑裂以及解决办法》

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)

Zookeeper有哪几种几种部署模式?

三种部署模式:

· 单机部署:一台集群上运行
· 集群部署:多台集群运行
· 伪集群部署:一台集群启动多个 Zookeeper实例运行

zookeeper为什么是小集群部署,为什么适合读多写少的场景

https://www.yuque.com/docs/share/2c00f515-9067-4228-a38d-c1b14fa90eb8?# 《zookeeper为什么是小集群部署,为什么适合读多写少的场景》

集群最少要几台机器,集群规则是怎样的?集群中有 3 台服务器,其中一个节点宕机,这个时候 Zookeeper 还可以使用吗?

集群规则为 2N+1 台,N>0,即 3 台。可以继续使用,单数服务器只要没超过一半的服务器宕机就可以继续使用。

集群支持动态添加机器吗

其实就是水平扩容了,Zookeeper 在这方面不太好。两种方式:

全部重启:关闭所有 Zookeeper 服务,修改配置之后启动。不影响之前客户端的会话。

逐个重启:在过半存活即可用的原则下,一台机器重启不影响整个集群对外提供服务。这是比较常用的方式。

3.5 版本开始支持动态扩容。