Zookeeper 集群工作原理

Zookeeper集群工作原理

Zookeeper 作为一个分布式协调组件,很多应用系统都会依赖Zookeeper来实现相关业务的处理,在分布式架构中任何节点都不能以单点状态存在,所以Zookeeper首先需要解决的是单点故障问题,而常见的解决方案就是做主从集群

一、集群需要满足哪些功能?

  • 集群中要有主节点和从节点(也就是集群要有角色)
  • 集群要能做到数据同步,当主节点出现故障时,从节点能够顶替主节点继续工作,但是继续工作的 前提是数据必须要主节点保持一直
  • 主节点挂了以后,从节点如何接替成为主节点,自动选举

首先,Zookeeper 集群中有几个关键的概念:Leader、Follower 和 Observer

Zookeeper 中通常只有 Leader 节点可以写入,Follower 和 Observer 都只是负责读,但是 Follower 会参与节点的选举和过半写成功,Observer 则不会,他只是单纯的提供读取数据的功能。

通常这样设置的话,是为了避免太多的从节点参与过半写的过程,导致影响性能,这样 Zookeeper 只要使用一个几台机器的小集群就可以实现高性能了,如果要横向扩展的话,只需要增加 Observer 节点即可。

Zookeeper 建议集群节点个数为奇数,只要超过一半的机器能够正常提供服务,那么整个集群都是可用的状态。
在这里插入图片描述

二、节点之间的数据同步

在分布式系统中,每一个机器节点虽然都能够明确知道自己进行的事务操作过程是成功和失败,但是却无法直接获取其他分布式节点的操作结果。
所以当一个事务操作涉及到跨节点的时候,就需要用到分布式事务,分布式事务的数据一致性协议有2PC协议

阶段一:提交事务请求(投票)

  1. 事务询问
    协调者向所有的参与者发送事务内容,询问是否可以执行事务提交操作,并开始等待各参与者的响应
  2. 执行事务
    各个参与者节点执行事务操作,并将Undo和Redo信息记录到事务日志中,尽量把提交过程中所有消耗时间的操作和准备都提前完成确保后面100%成功提交事务
  3. 各个参与者向协调者反馈事务询问的响应
    如果各个参与者成功执行了事务操作,那么就反馈给参与者 yes的响应,表示事务可以执行;如果参与者没有成功执行事务,就反馈给协调者 no的响应,表示事务不可以执行,上面这个阶段有点类似协调者组织各个参与者对一次事务操作的投票表态过程,因此2pc协议的第一个阶段称为“投票阶段”,即各参与者投票表名是否需要继续执行接下去的事务提交操作

阶段二:执行事务提交

在这个阶段,协调者会根据各参与者的反馈情况来决定最终是否可以进行事务提交操作,正常情况下包含两种可能:执行事务、中断事务

在Zookeeper中,采用少数服从多数的方式来实现数据同步,也就是不需要所有节点都在第一阶段给出明确的事务提交成功的回复,只需要大于半数节点都提交成功,那么Zookeeper认为该数据已经同步完成。

三、Zookeeper中的一致性

前面在讲Zookeeper的数据同步时,提到zookeeper并不是强一致性服务,它是一个最终一致性模型。
由于网络的延迟以及系统本身执行请求的不确定性,会导致请求发起的早的客户端不一定会在服务端执行得早。最终以服务端执行的结果为准。
zookeeper基于zxid以及阻塞队列的方式来实现请求的顺序一致性,如果客户端A和B要读取必须要读取到相同的值,那么client B在读取操作之前执行sync方法。 zooKeeper.sync();

简单来说:顺序一致性是针对单个操作,单个数据对象。属于CAP中C这个范畴。一个数据被更新后,能够立马被后续的读操作读到。zookeeper不保证在每个实例中,两个不同的客户端具有相同的zookeeper数据视图,由于网络延迟等因素,一个客户端可能会在另外一个客户端收到更改通知之前执行更新

四、ZAB协议

ZAB(Zookeeper Atomic Broadcast) 协议是为分布式协调服务 ZooKeeper 专门设计的一种支持崩溃恢复的原子广播协议。在 ZooKeeper 中,主要依赖 ZAB 协议来实现分布式数据一致性,基于该协议来保持集群中各个副本之间的数据一致性。

ZAB 包含两种基本模式,崩溃恢复和消息广播

整个集群服务在启动、网络中断或者重启等异常情况的时候,首先会进入到崩溃恢复状态,此时会通过选举产生 Leader 节点,当集群过半的节点都和 Leader 状态同步之后,ZAB 就会退出恢复模式。之后,就会进入消息广播的模式。

4.1、消息广播

  1. leader接收到消息请求后,将消息赋予一个全局唯一的64位自增id,叫:zxid(zxid是一个长度64位的数字,其中低32位是按照数字递增,即每次客户端发起一个proposal,低32位的数字简单加1。高32位是leader周期的epoch编号),通过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的投票过程,不需要Observer的ack,也就是Observer不需要参与投票过程,但是Observer必须要同步Leader的数据从而在处理请求的时候保证数据的一致性

4.2、崩溃恢复

崩溃恢复状态下zab协议需要做两件事

  1. 选举出新的leader
  2. 数据同步

数据同步有两个准则:

  • 已经被处理的消息不能丢弃
    当 leader 收到合法数量 follower 的 ACKs 后,就向各个 follower 广播 COMMIT 命令,同时也会在本地执行 COMMIT 并向连接的客户端返回「成功」,但是如果在各个 follower 在收到 COMMIT 命令前leader 就挂了,ZAB协议就需要确保消息不能丢弃
  • 被丢弃的消息不能再次出现
    当 leader 接收到消息请求生成 proposal 后就挂了,其他 follower 并没有收到此 proposal,经过恢复模式重新选了 leader 后,这条消息是被跳过的,不能再次出现

在进行数据同步前,Leader 服务器会完成数据同步初始化,数据同步通常分为四类:
1、直接差异化同步(DIFF 同步)
2、先回滚再差异化同步(TRUNC+DIFF 同步)
3、仅回滚同步(TRUNC 同步)
4、全量同步(SNAP 同步)

peerLastZxid: 从 follower 服务器注册时发送的 ACKEPOCH 消息中提取 lastZxid(该follower 服务器最后处理的 ZXID)
minCommittedLog:Leader 服务器 Proposal 缓存队列 committedLog 中最小 ZXID
maxCommittedLog:Leader 服务器 Proposal 缓存队列 committedLog 中最大 ZXID

直接差异化同步(DIFF 同步)
peerLastZxid 介于 minCommittedLog 和 maxCommittedLog之间
先回滚再差异化同步
当新的 Leader 服务器发现某个 follower 服务器包含了一条自己没有的事务记录,那么就需要让该 Learner 服务器进行事务回滚–回滚到 Leader服务器上存在的,同时也是最接近于 peerLastZxid 的 ZXID
仅回滚同步(TRUNC 同步)
peerLastZxid 小于 minCommittedLog
:Leader 服务器上没有 Proposal 缓存队列且 peerLastZxid 不等于 lastProcessZxid
全量同步(SNAP 同步
peerLastZxid 大于 maxCommittedLog全量同步(SNAP 同步)

五、 如何进行 Leader 选举的?

选举主要包含事务 zxid 和 myid,节点主要包含 LEADING\FOLLOWING\LOOKING 3 个状态。

  • myid 服务器ID
    比如有三台服务器,编号分别是1,2,3。编号越大在选择算法中的权重越大。
  • zxid 事务id
    值越大说明数据越新,在选举算法中的权重也越大
  • 逻辑时钟(epoch – logicalclock)或者叫投票的次数
    同一轮投票过程中的逻辑时钟值是相同的。每投完一次票这个数据就会增加,然后
    与接收到的其它服务器返回的投票信息中的数值相比,根据不同的值做出不同的判断

5.1、服务启动期间的选举

  • 1、首先,每个节点都会对自己进行投票,每次投票会包含所推举的服务器的myid和zxid 、epoch,使用(myid, zxid ,epoch)来表示,比如Server1的投票为(1, 0,0),Server2的投票为(2, 0,0),,然后把投票信息广播给集群中的其他节点
  • 节点接收到其他节点的投票信息,首先判断该投票的有效性,如检查是否是本轮投票(epoch)、是否来自LOOKING状态的服务器,然后和自己的投票进行比较
    • 优先比较epoch
    • 其次检查zxid ,zxid 比较大的服务器优先作为Leader
    • 最后就比较myid,myid较大的服务器作为Leader

5.2、运行过程中的leader选举

如果开始选举出来的 leader 节点宕机了,那么运行期间就会重新进行 leader 的选举。
选举基本过程和之前是一致的

  • leader 宕机之后,非 observer 节点都会把自己的状态修改为 LOOKING 状态,然后重新进入选举流程
  • 生成投票信息(myid,zxid,epoch),同样,第一轮的投票大家都会把票投给自己,然后把投票信息广播出去
  • 接下来的流程和上面的选举是一样的,最后统计投票信息,修改节点状态,选举结束

六、有可能会出现数据不一致的问题

6.1、查询不一致
因为 Zookeeper 是过半成功即代表成功,假设我们有 5 个节点,如果 123 节点写入成功,如果这时候请求访问到 4 或者 5 节点,那么有可能读取不到数据,因为可能数据还没有同步到 4、5 节点中,也可以认为这算是数据不一致的问题。

解决方案:在读取前使用 sync 命令。

6.2、leader 未发送 proposal 宕机

这就是上面说过的问题。leader 刚生成一个 proposal,还没有来得及发送出去,此时 leader 宕机,重新选举之后作为 follower,但是新的 leader 没有这个 proposal。这种场景下的日志将会被丢弃。
6.3、leader 发送 proposal 成功,发送 commit 前宕机

如果发送 proposal 成功了,但是在将要发送 commit 命令前宕机了,如果重新进行选举,还是会选择 zxid 最大的节点作为 leader,因此,这个日志并不会被丢弃,会在选举出 leader 之后重新同步到其他节点当中。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值