ZooKeeper理论基础

1 ZooKeeper简介

ZooKeeper由雅虎研究院开发,后来捐赠给了Apache。ZooKeeper是一个开源得分布式应用程序协调服务器,其为分布式系统提供一致性服务。其一致性是通过基于Paxos算法得ZAB协议完成得。主要包括:配置维护,域名服务,分布式同步,集群管理等。

2 一致性

zk是如何保证分布式系统得一致性呢?是因为zk具有以下几方面特点:顺序一致,原子性,单一视图,可靠性和最终一致性。

2.1 顺序一致性

从同一个客服端发起得多个事务请求(写操作请求),最终会严格按照其发起顺序记录zk中。

2.2 原子性

所有事务请求得结果在集群中所有server上得应用情况是一致得。要么全部应用成功,要么都失败。不会出现部分成功或部分失败得情况

2.3 单一视图

无论客户端连接的是集群中的哪台Server,其读取到数据模型中的数据都是一致的。

2.4 可靠性

一旦某事务被成功应用到了zk,则会一直被保留下来,除非另一个事务将其修改。

2.5 最终一致性

一旦一个事务被成功应用,zk可以保证在一段较短的时间内同步数据,客户端最终一定能够从服务端读取到最新的数据。但不能保证实时读取到。

3 ZAB协议

3.1 ZAB协议简介

ZAB ,Zookeeper Atomic Broadcast,zk 原子消息广播协议,是专为 ZooKeeper 设计的一种支持崩溃恢复的原子广播协议,在 Zookeeper 中,主要依赖 ZAB 协议来实现分布式数据一致性。
Zookeeper 使用一个单一主进程来接收并处理客户端的所有事务请求,即写请求。当服务器数据的状态发生变更后,集群采用 ZAB 原子广播协议,以事务提案 Proposal 的形式广播到所有的副本进程上。ZAB 协议能够保证一个全局的变更序列,即可以为每一个事务分配一个全局的递增编号 xid。
当 Zookeeper 客户端连接到 Zookeeper 集群的一个节点后,若客户端提交的是读请求,那么当前节点就直接根据自己保存的数据对其进行响应;如果是写请求且当前节点不是Leader,那么节点就会将该写请求转发给 Leader,Leader 会以提案的方式广播该写操作,只要有超过半数节点同意该写操作,则该写操作请求就会被提交。然后 Leader 会再次广播给所有订阅者,即 Learner,通知它们同步数据。
Zookeeper服务工作原理示意图

3.2 ZAB与Paxos的关系

ZAB 协议是 Paxos 算法的一种工业实现算法。但两者的设计目标不太一样。ZAB 协议主要用于构建一个高可用的分布式数据主从系统,即 Follower 是 Leader 的从机,Leader 挂了,马上就可以选举出一个新的 Leader,但平时它们都对外提供服务。而 Fast Paxos 算法则是用于构建一个分布式一致性状态机系统,确保系统中各个节点的状态都是一致的。

3.3 三类角色

  • Leader:事务请求的唯一处理者,也可以处理读请求

  • Follower:可以直接处理客户端的读请求,并向客户端响应;但不会处理事务请求,其只会将客户端事务请求转发给Leader来处理;对Leader发起的事务提案具有表决权;同步Leader中的事务处理结果;Leader选举过程的参与者,具有选举权与被选举权

  • Observer:可以理解为不参与Leader选举的Folower,在Leader选举过程中没有选举权被选举权;同时,对于Leader的提案没有表决权。用于协助Folower处理更多的客户端读请求。Observer的增加会提高集群读请求处理的吞吐量,但不会增加事务请求的通过压力,不会增加Leader选举的压力。
    问:Observer设置多少合适?是否越多越好?
    答:Observer数量与Follower数量相同较为合适,并不是越多越好(原因见:Observer的数量问题)

  • Learner:学习者,既要从Leader中同步数据的Server,既Follower+Observer.
    Leanrner=Follower+Observer

  • QuorumServer:QuorumPeer,Participant,法定服务器,法定主机,参与者。在集群正常服务状态下,具有表决权的服务器称为QuorumServer或QuorumPeer;在Leader选举过程中,具有选举权与被选举权的服务器,称为Participant。
    QuorumServer = Leader + Follower = Participant

3.4 三个数据

在ZAB中有三个很重要的数据
  • zxid:其为一个64位长度的Long类型,其中高32位标识epoch,低32位标识xid;
  • epoch:(时期,年号)每个Leader选举结束后都会产生一个新的epoch,并会通知到集群中所有其他Server,包含Follower和Observer。
  • xid:事务id,是一个流水号

3.5 三种模式

ZAB协议中对zkServer的状态描述有三种模式。这三种模式并没有十分明显的界线,它们相互交织在一起。	
  • 恢复模式:在集群启动过程中Leader崩溃后,系统都需要进入恢复模式,以恢复系统对外提供服务的能力。
    其中包含两个重要阶段:Leader选举初始化同步
  • 广播模式:分为两类,初始化广播与更新广播。
  • 同步模式:分为两类,初始化同步与更新同步。

3.6 四种状态

zk集群中每一台主机,在不同阶段会处于不同的状态,每一台主机具有四种状态。

  • LOOKING:选举状态
  • FOLLOWING:follower的正常工作状态
  • OBSERVING:observer的正常工作状态
  • LEADING:Leader的正常工作状态

3.7 同步模式与广播模式

(1) 初始化广播

恢复模式具有两个阶段:Leader选举与初始化同步(广播)。当完成Leader选举后,此时的Leader还是一个准Leader,要经过初始化同步后才能变为真正的leader.
初始化广播示意图
具体过程如下

  1. 为了保证Leader向Learner发送提案的有序,Leader会为每一个Leade服务器准备一个队列
  2. Leader将那些没有被各个Learner同步的事务封装为Proposal
  3. Leader将这些Proposal逐条发给Learner,并在每一个Proposal后都紧跟一个COMMIT消息,表示该事务已经被提交,Learner可以直接接受并执行
  4. Learner接收来自于Leader的Proposal,并将其更新到本地
  5. 当Learnet更新成功后,会向准Leader发送ACK信息
  6. Learnet服务器在收到来自Learner的ACK后就会将该Learner加入到真正可用的Follower列表或Observer列表。没有反馈ACK,或反馈了但Leader没有收到的Learner,Leader不会将其加入到相应列表

(2) 消息广播算法

当集群中的Learner完成了初始化状态同步,那么整个zk集群就进入到正常工作模式了。
如果集群中Learner节点收到客户端的事务请求,那么这Learner会将请求转发给Leader服务器。然后再执行如下具体过程:
更新广播算法示意图
具体过程文字解说如下

  1. Leader接收到事务请求后,为事务赋予一个全局唯一的64位自增,即zxid,通过zxid的大小比较即可实现事务的有序性管理,然后将事务封装为一个Proposal.
  2. Leader根据Follower列表获取到所有Follower,然后再将Proposal通过这些Follower的队列将提案发送给各个Follower.
  3. 当Follower接收到提案后,会先将提案的zxid 与本地记录的事务日志中的最大的zxid进行比较。若当前提案的 zxid 大于最大 zxid,则将当前提案记录到本地事务日志中,并向 Leader 返回一个 ACK。
  4. 当 Leader 接收到过半的 ACKs 后,Leader就会向所有Follower的队列发送COMMIT消息,向所有 Observer 的队列发送 Proposal。
  5. 当 Follower 收到 COMMIT 消息后,就会将日志中的事务正式更新到本地。当 Observer收到 Proposal 后,会直接将事务更新到本地。
  6. 无论是Follower还是Observer,在同步完成后都需要向Leader发送成功ACK。

(3) Observer的数据问题

Observer数据一般与Follower数量相同,并不是Observer越多越好。因为Observer数量的增多虽不会增加事务操作压力,但需要从Leader同步数据,Observer同步数据的时间是小于Follower同步数据的时间。当Follower同步数据完成后,Leader的Observer列表中的Observer主机将接收同步。那些完成同步的Observer将会进入到另一个对外资源浪费。所以,对于事务操作发送频繁的系统,不建议使用果断Observer.

  • Leader中存在两个关于Observer的列表:all(包含所有Observer)与service(包含与Leader同步过数据的Observer)
  • service列表是动态变化的。对于没有进入到service列表中的Observer,会通过心跳与Leader进行连接,一旦连接成功,马上就会从Leader同步数据,同步完成后向Leader发送ACK。Leader在接收到ACK后会将其添加到service列表
  • 若客户端连接上了不在service列表中的Observer,那么这个Observer是不能提供服务的。因为该Observer的状态不是Observering。这个状态是通过Observer与Leader间的心跳来维护
  • Leadr中对于Follower也同样存在两个列表,all与service功能与Observer相识。但不同代点,若Leadr收到Follower同步完成的ACK数量没有过半,则认为同步失败,会重新进行广播,让Follower重新进行同步。

3.8 恢复模式的三原则

集群正在启动过程Leader崩溃后,集群就进入恢复模式。对于恢复的数据状态需要遵从三个原则。

(1) Leader的主动出让原则

若集群中Leader收到Follower心跳数量没有过半,此时 Leader 会自认为自己与集群的连接已经出现了问题,其会主动修改自己的状态为 LOOKING,去查找新的 Leader。为了防止集群出现脑裂。
而其它Server由于有过半的主机认为已经丢失了Leader,所以它们会发起新的Leader选举,选出一个新的Leader。

(2) 已被处理过的消息不能丢原则

当Leader收到超过半数Fo’l’lower的ACDs后,就向各个Follower广播COMMIT消息,批准各个Server执行该写操作事务。当各个Server在接收到Leader的COMMIT消息后就会在本地执行该写操作,然后会向客户端响应写操作成功。
但是如果在非全部 Follower 收到 COMMIT 消息之前 Leader 就挂了,这将导致一种后果:部分 Server 已经执行了该事务,而部分 Server 尚未收到 COMMIT 消息,所以其并没有执行该事务。当新的 Leader 被选举出,集群经过恢复模式后需要保证所有 Server 上都执行了那些已经被部分 Server 执行过的事务。

(3) 被丢弃的消息不能再现原则

当在Leader新事务已经通过,其已经将该事务更新到了本地,但所有Follower还都没有收到COMMIT之前,Leader宕机了(比前面叙述的宕机更早),此时,所有Follower根本就不知道该Proposal的存在。当新的Leader选举出来,整个集群进入正常服务状态后,之前挂了的Leader主机重新启动并注册成为了Follower。若那个别人根本不知道Proposel还保留在那个主机,那么其数据就会比其他主机多出了内容,导致整个系统状态的不一致。所以,该Proposa应该被丢弃。类似这样应该被丢弃的事务,是不能再次出现在集群中的,应该被清除。

3.9 Leader选举

在集’群启动过程中‘或’Leader 宕机后‘,集群就进入了恢复模式。恢复模式中最重要的阶段就是 Leader 选举。

(1) Leader选举中的基本概念

A. myid

myid也称为 ServerId。这是 zk 集群中服务器的唯一标识。eg:有三个 zk 服务器,那么编号分别是 1,2,3。

B.逻辑时钟

逻辑时钟‘Logicalclock’是一个整型数,该概念在选举时称为logicalclock,而在选举结束后称为epoch。即 epoch 与 logicalclock是同一个值,在不同情况下的不同名称。

(2)Leader选举算法

在集群启动过程中的Leader选举过程(算法)与Leader断连后的Leader选举过程稍微有一些区别,基本相同。

A.集群启动中的Leader选举

若进行 Leader 选举,则至少需要两台主机,这里以三台主机组成的集群为例。
集群启动时的Leader选举示意图
在集群初始化阶段,当第一台服务器Server1启动时,其会给自己投票,然后发布自己的投票结果。投票包含所推举的服务器的 myid 和 ZXID,使用(myid, ZXID)来表示,此时Server1的投票为(1, 0)。由于其它机器还没有启动所以它收不到反馈信息,Server1 的状态一直属于Looking,即属于非服务状态。
当第二台服务器 Server2 启动时,此时两台机器可以相互通信,每台机器都试图找到Leader,选举过程如下:

  1. 每个Server发出一个投票。此时Server1的投票为(1, 0),Server2的投票为(2, 0),然后各自将这个投票发给集群中其他机器。
  2. 接受来自各个服务器的投票。集群的每个服务器收到投票后,首先判断该投票的有效性,如检查是否是本轮投票、是否来自LOOKING状态的服务器。
  3. 处理投票。针对每一个投票,服务器都需要将别人的投票和自己的投票进行 PK,PK规则如下:
    a. 优先检查 ZXID。ZXID 比较大的服务器优先作为 Leader。
    b. 如果 ZXID 相同,那么就比较 myid。myid 较大的服务器作为 Leader 服务器。
    对于Server1而言,它的投票是(1, 0),接收Server2的投票为(2, 0)。其首先会比较两者的 ZXID,均为 0,再比较 myid,此时Server2的myid最大,于是Server1更新自己的投票为(2, 0),然后重新投票。对于Server2而言,其无须更新自己的投票,只是再次向集群中所有主机发出上一次投票信息即可。
  4. 计投票。每次投票后,服务器都会统计投票信息,判断是否已经有过半机器接受到相同的投票信息。对于Server1、Server2 而言,都统计出集群中已经有两台主机接受了(2, 0)的投票信息,此时便认为已经选出了新的Leader,即Server2。
  5. 改变服务器状态。一旦确定了Leader,每个服务器就会更新自己的状态,如果是Follower,那么就变更为FOLLOWING,如果是Leader,就变更为LEADING。
  6. 添加主机。在新的 Leader 选举出来后 Server3 启动,其想发出新一轮的选举。但由于当前集群中各个主机的状态并不是 LOOKING,而是各司其职的正常服务,所以其只能是以Follower 的身份加入到集群中。

B.宕机后的eader选举

在 Zookeeper 运行期间,Leader与非Leader服务器各司其职,即便当有非Leader服务器宕机或新加入时也不会影响Leader。但是若Leader服务器挂了,那么整个集群将暂停对外服务,进入新一轮的Leader选举,其过程和启动时期的Leader选举过程基本一致。
Leader宕机后Leader选举示意图
假设正在运行的有 Server1、Server2、Server3 三台服务器,当前 Leader 是 Server2,若某一时刻 Server2 挂了,此时便开始新一轮的 Leader 选举了。选举过程如下:

  1. 变更状态。Leader挂后,余下的非Observer服务器都会将自己的服务器状态由FOLLOWING变更为LOOKING,然后开始进入 Leader 选举过程。
  2. 每个Server会发出一个投票,仍然会首先投自己。不过在运行期间每个服务器上的ZXID可能是不同,此时假定 Server1的ZXID为111,Server3的ZXID为 333;在第一轮投票中Server1和Server3都会投自己,产生投票(1, 111),(3, 333),然后各自将投票发送给集群中所有机器。
  3. 接收来自各个服务器的投票(与启动时过程相同)。集群的每个服务器收到投票后,首先判断该投票的有效性,如检查是否是本轮投票、是否来自LOOKING状态的服务器。
  4. 处理投票(与启动时过程相同)。针对每一个投票,服务器都需要将别人的投票和自己的投票进行PK。对于Server1而言,它的投票是(1, 111),接收Server3的投票为(3, 333)。首先会比较两者的ZXID,Server3投票的zxid为333大于Server1投票的zxid 的 111,于是Server1更新自己的投票为(3, 333),然后重新投票。对于Server3而言,其无须更新自己的投票,只是再次向集群中所有主机发出上一次投票信息即可。
  5. 统计投票。与启动时过程相同。对于Server1、Server2而言,都统计出集群中已经有两台主机接受了(3, 333)的投票信息,此时便认为已经选出了新的Leader,即Server3。
  6. ) 改变服务器的状态(与启动时过程相同)。一旦确定了Leader,每个服务器就会更新自己的状态。Server1变更为FOLLOWING,Server3变更为LEADING。

4.高可用集群容灾

4.1 服务器数量的奇数与偶数

前面我们说过,无论是写操作投票,还是 Leader 选举投票,都必须过半才能通过。也就是说若出现超过半数的主机宕机,则投票永远无法通过。基于该理论,由 5 台主机构成的集群,最多只允许 2 台宕机。而由 6 台构成的集群,其最多也只允许 2 台宕机。即:6 台与5 台的容灾能力是相同的。基于此容灾能力的原因,建议使用奇数台主机构成集群,以避免资源浪费。
  但从系统吞吐量上说,6 台主机的性能一定是高于 5 台的。所以使用 6 台主机并不是资源浪费。

4.2 容灾设计方案

对于一个高可用的系统,除了要设置多台主机部署为一个集群避免单点问题外,还需要考虑将集群部署在多个机房、多个楼宇。对于多个机房、楼宇中集群也是不能随意部署的,下面就多个机房的部署进行分析。
在多机房部署设计中,要充分考虑“过半原则”,也就是说,尽量要确保 zk 集群中有过半的机器能够正常运行。

(1) 三机房部署

在生产环境下,三机房部署是最常见的、容灾性最好的部署方案。
  三机房部署中要求每个机房中的主机数量必须少于集群总数的一半。这样可以保证,三个机房中若有一个机房断电或断网,其它两个机房中的机器总数仍是过半的,集群仍可以正常对外提供服务。当然,若两个机房出现了问题,那么整个集群就瘫痪了。这种情况出现的概率要远低于一个机房出问题的情况。

(2) 双机房部署

zk 官网没有给出较好的双机房部署的容灾方案。只能是让其中一个机房占有超过半数的主机,使其做为主机房,而另一机房少于半数。当然,若主机房出现问题,则整个集群会瘫痪。

5.CAP定理

5.1 简介

CAP定理指的是在一个分布式系统中,Consistency(一致性)、Availability(可用性)、Partition tolerance(分区容错性),三者不可兼得。

  • 一致性©:分布式系统中多个主机之间是否能够保持数据一致的特性。即当系统数据发生更新操作后,各个主机中的数据仍然处于一致的状态。
  • 可用性(A):系统提供的服务必须一直处于可用的状态,即对于用户的每一个请求,系统总是可以在有限的时间内对用户做出响应
  • 分区容错性§:分布式系统在遇到任何网络分区故障时,仍能够保证对外提供满足一致性和可用性的服务。

对于分布式系统,网络环境相对是不可控的,出现网络分区是不可避免的,因此系统必须具备分区容错性。但其并不能同时保证一致性与可用性。CAP原则对于一个分布式系统来说,只可能满足两项,即要么CP,要么AP。

5.2 BASE理论

  • BASE 是 Basically Available(BA基本可用)、Soft state(S软状态)和 Eventually consistent(E最终一致性)三个短语的简写。是 CAP 定理对于一致性与可用性权衡的结果。
  • BASE 理论的核心思想是:即使无法做到强一致性,但每个系统都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性。

(1) 基本可用

基本可用是指分布式系统在出现不可预知故障的时候,允许损失部分可用性。(响应时间的损失、功能上的损失)

(2) 软状态

软状态是指允许系统数据存在的中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统主机间进行数据同步的过程存在一定延时。软状态其实就是一种灰度状态,过渡状态。

(3) 最终一致性

最终一致性强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。

5.3 ZK与CP

问:zk遵循的是CP原则,即保证了一致性,但牺牲了可用性。体现在哪里呢?
答:当Leader宕机后,zk集群会马上进行新的Leader的选举。但选举时长一般在200毫秒内,最长不超过 60 秒,整个选举期间zk集群是不接受客户端的读写操作的,即zk集群是处于瘫痪状态的。所以其不满足可用性。

6.zk可能会存在脑裂

这里说的zk可能会引发脑裂,是指的在多机房部署中,若出现了网络连接问题,形成多个分区,则可能会出现脑裂问题,可能会导致数据不一致。

参考:
开课吧
《从Paxos到ZooKeeper分布式一致性原理与实践》

发布了3 篇原创文章 · 获赞 1 · 访问量 65

猜你喜欢

转载自blog.csdn.net/langzhouxing/article/details/103741247
今日推荐