ZooKeeper工作原理

1. ZooKeeper工作原理

1.1 ZooKeeper角色

  • 领导者(Leader):在Zookeeper集群中,Leader是负责管理集群事务的节点。它负责处理所有的写请求,并将这些请求转化为事务,并提交事务日志。Leader节点还负责发起和决议投票过程,以及更新系统状态。

  • 学习者(Learner):学习者是Zookeeper中用于接收客户端请求并返回结果的节点。学习者分为两种类型:

    • 跟随者(Follower):跟随者是学习者的一种,它们参与到Zookeeper的投票过程中,帮助选举出Leader,并且同步Leader的状态。跟随者也可以处理客户端的读请求。

    • 观察者(Observer):观察者也是学习者的一种,但它们不参与投票过程。观察者的主要作用是接收客户端的连接,并将写请求转发给Leader。它们只同步Leader的状态,不参与决策过程,这样可以提高系统的读取性能。

  • 客户端(Client):客户端是请求发起方,它们与Zookeeper集群交互,发起读写请求。客户端可以是任何需要与Zookeeper交互的应用程序或服务。

image-20240812112057576

image-20240812112112622

1.2 ZooKeeper核心机制

Zookeeper的核心机制是原子广播,它确保了分布式系统中各个服务器(Server)之间的状态同步。实现这一机制的协议是Zab(Zookeeper Atomic Broadcast)协议。

1.2.1 Zab协议

Zab协议定义了两种模式:

  • 恢复模式(选主):当服务启动或者当前领导者崩溃后,Zab进入恢复模式。在这个阶段,系统的主要任务是选举出一个新的领导者。

  • 广播模式(同步):一旦领导者被选举出来,并且大多数服务器与领导者完成了状态同步,系统就从恢复模式切换到广播模式。在广播模式下,领导者负责处理客户端的写请求,并将这些请求广播给所有服务器,以确保数据的一致性。

1.2.2 事务ID(Zxid)

为了保证事务的顺序一致性,Zookeeper使用递增的事务ID号(zxid)来标识每个事务。Zxid是一个64位的数字,分为两部分:

  • 高32位(Epoch):用于标识领导者关系是否改变。每当一个新的领导者被选举出来,Epoch值会增加,表示进入了一个新的领导者统治时期。

  • 低32位:用于递增计数,确保每个事务都有一个唯一的标识。

  • Zookeeper中的Zxid是一个64位的数字,用于确保事务的顺序一致性。Zxid由两部分组成:高32位是epoch,用于标识Leader关系是否改变,每次选出新的Leader时,都会有一个新的epoch;低32位是递增计数,用于记录事务的顺序。当Zxid的低32位达到最大值(即2^32-1)时会发生溢出,此时会触发集群重新选举,然后Zxid会变为0,日志中会记录相应的信息,例如“zxid lower 32 bits have rolled over, forcing re-election, and therefore new epoch start”。Zxid达到最大值后,集群会强制进行选主,并重置Zxid低32位的计数值,高32位变为新Leader的周期,低32位变为0。目前,没有避免Zxid溢出的方法,但业务侧可以提前规避相关风险

1.2.3 服务器状态

每个服务器在工作过程中可能处于以下三种状态之一:

  • LOOKING:服务器当前不知道领导者是谁,正在寻找领导者。

  • LEADING:服务器当前被选举为领导者,负责处理事务和与跟随者同步状态。

  • FOLLOWING:领导者已经选举出来,服务器与之同步,接收并应用领导者广播的事务。

通过这些机制,Zookeeper能够确保分布式系统中的数据一致性和高可用性,即使在领导者崩溃的情况下也能快速恢复并继续提供服务。

1.2.4 ZooKeeper读写机制

  • 集群结构:Zookeeper由多个服务器(Server)组成的集群,这些服务器可以分布在不同的物理位置。

  • 领导者(Leader)和跟随者(Follower):集群中有一个领导者(Leader),负责处理所有的写请求。跟随者(Follower)是集群中的其他服务器,它们主要负责处理读请求和同步领导者的状态。

  • 数据副本:每个服务器都保存着一份数据的副本。这些副本在正常情况下应该是完全一致的,以保证数据的全局一致性。

  • 分布式读写:Zookeeper支持分布式读写操作。客户端可以向任何一个服务器发起读写请求。

  • 更新请求转发:当客户端向跟随者发起写请求时,这个请求会被转发到领导者。领导者负责实施这些更新操作。

  • 事务处理:领导者使用Zab协议来处理事务。写请求被转化为事务,并分配一个唯一的事务ID(zxid)。领导者将事务日志广播给所有跟随者。

  • 数据同步:跟随者接收到领导者广播的事务日志后,会更新自己的数据副本,以确保与领导者的数据一致。

  • 读请求处理:对于读请求,跟随者可以直接处理,因为它们的数据副本是与领导者同步的。这样可以提高系统的读取性能,因为读操作不需要经过领导者。

  • 故障恢复:如果领导者发生故障,Zookeeper会通过Zab协议的恢复模式选举出新的领导者,并确保所有跟随者与新领导者的数据副本同步。

1.2.5 Zookeeper节点数据操作流程

  • 客户端请求写操作:Client 发出一个写请求到集群中的任意一个 Follower。

  • Follower 转发请求:收到写请求的 Follower 将请求转发给当前的 Leader。

  • Leader 发起投票:Leader 收到写请求后,会创建一个事务提案(Proposal),并为其分配一个唯一的 ZXID。然后,Leader 将这个提案发送给所有 Follower,请求它们进行投票。

  • Follower 发送投票结果:Follower 收到提案后,会根据自身的数据状态和配置对提案进行投票,并将投票结果发送回 Leader。

  • Leader 汇总投票结果:Leader 等待收到超过半数的 Follower 的投票响应。如果提案获得多数 Follower 的同意,Leader 决定将提案进行提交。

  • Leader 写入并提交事务:Leader 在本地将提案写入事务日志,并更新内存中的数据状态,然后向所有 Follower 发送提交(Commit)指令。

  • Follower 应用事务:Follower 收到 Commit 指令后,也会将该提案写入本地事务日志,并更新内存中的数据状态,以保证数据的一致性。

  • Follower 返回结果给 Client:一旦 Follower 完成写入操作,它会将写操作的结果返回给原始请求的 Client。

  • Client 接收响应:Client 接收到来自 Follower 的写操作结果,整个写请求流程完成。

1.2.6 Follower的主要职责

  • 发送请求给Leader:Follower定期向Leader发送PING消息以确认连接的有效性,发送REQUEST消息请求投票或同步,以及发送ACK消息确认接收到的提案或命令。

  • 接收并处理Leader的消息:Follower接收来自Leader的指令和提案,并据此更新自己的状态和数据。

  • 转发Client写请求:对于客户端的写请求,Follower将其转发给Leader,由Leader来协调整个集群的数据一致性。

  • 返回结果给Client:在处理完来自客户端的请求后,无论是读请求还是转发的写请求的结果,Follower都会将结果返回给客户端。

1.2.7 Follower处理的来自Leader的消息类型

  • PING消息:这是心跳消息,用于维持Follower与Leader之间的连接,确保Follower知道Leader仍然可用。

  • PROPOSAL消息:当Leader需要对某个事务进行投票时,会向所有Follower发送PROPOSAL消息,Follower收到后需要对提案进行投票。

  • COMMIT消息:一旦提案获得多数Follower的同意,Leader会发送COMMIT消息给所有Follower,指示它们将提案正式提交到本地日志并更新状态。

  • UPTODATE消息:这表明Follower与Leader的数据已经同步完成,Follower是最新的。

  • REVALIDATE消息:这是Leader对Follower上的某个session进行验证的结果,可能要求Follower关闭该session或允许其继续接收消息。

  • SYNC消息:这是对客户端发起的SYNC请求的响应,客户端可能需要确保从Follower获取到最新的数据更新。

1.2.8 Zookeeper leader选举

  • 半数通过原则:在Zookeeper集群中,确实需要超过半数的服务器同意才能选出一个新的Leader。对于3台服务器的集群,需要至少2台同意;对于4台服务器的集群,需要至少3台同意。   

    • 3台机器 挂一台 2>3/2    

    • 4台机器 挂2台 2!>4/2

  • 选举过程

    • 初始时,所有服务器都处于LOOKING状态,即它们都在寻找Leader。

    • 每个服务器都发出一个提议(Proposal),提议自己成为Leader,并开始接收其他服务器的投票。

  • 投票

    • 服务器之间相互投票,每个服务器会收到来自其他服务器的提议,并根据自己的逻辑时钟(ZXID)和服务器ID(myid)来决定是否同意这个提议。

    • ZXID较大的提议会优先获得投票,如果XZID相同,则会选择myid较大的服务器。

  • 超过半数同意

    • 一旦某个服务器获得了超过半数的投票,它就认为自己被选举为Leader,并开始向其他服务器发送确认消息。

  • 结束选举

    • 当一个服务器获得足够的投票成为Leader后,选举结束。其他服务器在收到足够多的确认消息后,会停止自己的选举过程,并进入FOLLOWING状态,服从新Leader的命令。

  • 提案的无效性

    • 如果一个服务器在选举过程中收到了另一个服务器已经成为Leader的确认消息,它会停止自己的选举过程,并接受这个事实,即使自己可能已经开始了一个新的提案。

  • 启动顺序

    • 谁先启动并不能决定谁成为Leader。Leader的选举是基于投票和确认消息的,而不是简单地基于启动顺序。

  • ZXID和myid的重要性

    • ZXID和myid是选举过程中的关键因素。ZXID用于确保事务的全局顺序性,而myid是服务器的唯一标识符,它们共同决定了选举的结果。

1.2.9 ZooKeeper仲裁区

  • Zookeeper的仲裁区(Quorum)是指在Zookeeper的仲裁模式(Quorum Mode)下,由多台服务器组成的集群,这些服务器协同工作,同时服务客户端的请求。仲裁模式是Zookeeper的默认运行模式,也是最常用的一种模式。在仲裁模式下,为了保证系统的可用性和可靠性,需要至少三台服务器组成一个奇数个节点的集群,这样可以确保在有服务器宕机的情况下,仍然能够选出一个Leader,继续提供服务。

  • 在仲裁模式中,Zookeeper集群中的每个服务器都会保存整个数据集的副本,客户端连接到集群中的任一服务器进行读写操作。集群中的服务器通过投票机制来达成一致性,选出一个Leader服务器,由Leader负责处理写请求,而读请求可以在任何一个服务器上执行。

  • 搭建Zookeeper仲裁模式的步骤主要包括:准备服务器、配置服务器、启动服务器和创建数据节点。在配置服务器时,需要在ZooKeeper的配置文件(zoo.cfg)中指定每个服务器的ID和地址,以及指定集群中的其他服务器。例如,可以设置server.1=zoo1:2888:3888,其中server.ID=HOST:PORT1:PORT2,ID是服务器的唯一标识,HOST是服务器的主机名或IP地址,PORT1用于服务器之间的数据同步,PORT2用于Leader选举。

  • 在仲裁模式下,Zookeeper集群能够提供高可用性和强一致性的服务,适用于生产环境和分布式系统的协调管理。

1.2.10 选举过程

  • A提案说,我要选自己,B你同意吗?C你同意吗?B说,我同意选A;C说,我同意选A。注意,这里超过半数了,其实在现实世界选举已经成功了。但是计算机世界是很严格,另外要理解算法,要继续模拟下去。)

  • 接着B提案说,我要选自己,A你同意吗;A说,我已经超半数同意当选,你的提案无效;C说,A已经超半数同意当选,B提案无效。

  • 接着C提案说,我要选自己,A你同意吗;A说,我已经超半数同意当选,你的提案无效;B说,A已经超半数同意当选,C的提案无效。

  • 选举已经产生了Leader,后面的都是follower,只能服从Leader的命令。而且这里还有个小细节,就是其实谁先启动谁当头。

image-20240812143259628

1.3 ZooKeeper集群数目

Zookeeper集群的数目通常选择为奇数个,这主要是基于以下几个原因:

  • 基于Paxos协议的Leader选举:Zookeeper使用基于Paxos协议的变种ZAB(Zookeeper Atomic Broadcast)协议来实现Leader选举。Paxos协议的核心思想是多数写入即成功,即如果集群中的多数节点(超过半数)能够写入某个值,则认为这个操作成功。

  • 容错能力:在一个由奇数个节点组成的Zookeeper集群中,如果集群中的一半以上节点存活,集群就能正常工作。例如,一个3节点的集群可以容忍1个节点的故障,而4节点的集群也只能容忍1个节点的故障。因此,从容错角度来看,3节点和4节点的容错能力相同。

  • 避免脑裂:如果集群中的节点数量是偶数,那么在网络分区或其他故障情况下,可能会发生所谓的"脑裂"现象,即集群分裂成两个独立的小组,每个小组都认为自己是集群的合法领导者。奇数个节点可以减少这种情况的发生,因为不可能有两个相同的多数。

  • 资源利用效率:由于3节点和4节点的容错能力相同,选择3节点可以节省服务器资源。如果选择5节点,虽然可以容忍2个节点的故障,但在大多数情况下,这可能是一种资源的过度配置。

  • 投票效率:在奇数个节点的集群中,当进行Leader选举或其他需要多数同意的操作时,可以更快地得出结果,因为奇数的一半总是一个整数,而偶数的一半是一个小数,需要向上取整,这可能会导致更多的投票轮次。

1.4 ZooKeeper 的节点

Zookeeper的节点,也称为znode,是Zookeeper中数据结构的基本单元,类似于文件系统中的文件和目录。每个znode都包含了数据和相关的状态信息,并且可以有子节点。以下是Zookeeper中znode的四种类型:

  1. 持久化节点 (PERSISTENT)

    • 这类节点一旦被创建,就会永久保存在Zookeeper中,直到被客户端显式地删除。

    • 即使创建它的客户端会话结束,持久化节点也会继续存在。

  2. 短暂节点 (EPHEMERAL)

    • 短暂节点与客户端会话绑定。如果客户端会话结束(无论是因为网络问题还是客户端崩溃),Zookeeper将自动删除这个短暂节点。

    • 短暂节点不允许有子节点,这确保了当客户端会话结束时,不会有遗留的子节点。

  3. 持久化顺序编号节点 (PERSISTENT_SEQUENTIAL)

    • 这种类型的节点具有持久化节点的所有特性,但增加了顺序编号的元素。

    • 当创建一个持久化顺序编号节点时,Zookeeper会根据当前已存在的顺序编号最大的节点,递增编号来创建新节点。

    • 这种类型的节点常用于需要有序列表的场景。

  4. 短暂顺序编号节点 (EPHEMERAL_SEQUENTIAL)

    • 短暂顺序编号节点结合了短暂节点和顺序编号的特性。

    • 这类节点在客户端会话结束时会被删除,同时它们也会被赋予一个唯一的顺序编号。

    • 这适用于实现需要临时有序集合的场景。

  • 11
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值