JavaEE 企业级分布式高级架构师(八)Zookeeper学习笔记(1)

Zookeeper理论基础

Zookeeper简介

  • Zookeeper由雅虎研究院开发,后来捐赠给了 Apache。Zookeeper 是一个开源的分布式应用程序协调服务器,其为分布式系统提供一致性服务。其一致性是通过 Paxos 算法的 ZAB 协议完成的。其主要功能包括:配置维护域名服务分布式同步集群管理等。
  • Zookeeper的官网:http://zookeeper.apache.org/
    在这里插入图片描述
    【原文】ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services.
    【翻译】ZooKeeper是一种集中式服务,用于维护配置信息,命名(域名服务),提供分布式同步和提供组服务(集群管理)。

一致性

Zookeeper的一致性主要体现在以下几个方面:

  • 顺序一致性:同一个ZooKeeper客户端发起的事务请求(写请求),最终会以非常严格的顺序写入到ZooKeeper,即来自客户端的更新将严格按照客户端发送的顺序处理;
  • 原子性:所有的事务请求(请求),它所影响的结果,在集群里的每一个节点上的应用情况都是一样的,即更新或者成功或者失败,不存在部分成功或者部分失败的场景;
  • 单一视图:客户端取ZooKeeper集群中任何一个节点上的信息都应该是一致的(原子性决定的),即无论客户端连接到哪个服务器,看到的都是一样的视图;
  • 可靠性:ZooKeeper服务器对于客户端的每一次事务请求(请求)的修改应该是可靠的,即不会存在丢失的情况,即一旦一个更新生效,它将一直保留,直到再次更新;
  • 最终一致性:在特定的一段时间内,任何系统的改变都能被客户端看到,或者被监听到,客户端读到的信息都是最新的、一致的。

Paxos算法

对于Zookeeper理论的学习,最重要的也是最难的知识点就是Paxos算法,所以我们首先学习 Paxos 算法。

算法简介

  • Paxos算法是 莱斯利·兰伯特(Leslie Lamport) 1990年提出的一种基于消息传递、具有高容错性的一致性算法。Google Chubby的作者 Mike Burrows 说过,世上只有一种一致性算法,那就是 Paxos 算法,所有其他一致性算法都是 Paxos 算法的不完整版。Paxos 算法是一种公认的晦涩难懂的算法,并且工程实现上也具有很大的难度。较有名的 Paxos 工程实现有 Google Chubby、ZAB、微信 PhxPaxos等。

Paxos与拜占庭将军问题

  • 拜占庭将军问题是由Paxos算法作者 莱斯利·兰伯特 提出的点对点通信中的基本问题。该问题要说明的含义是:在不可靠信道上试图通过消息传递的方式达到一致性是不可能的。所以,Paxos算法的前提是不存在拜占庭将军问题,即信道是安全的、可靠的,集群节点间传递的消息是不会被篡改的。
    在这里插入图片描述
  • 一般情况下,分布式系统中各个节点间采用两种通讯模型:共享内存(Shared Memory)、消息传递(Messages Pssing)。而Paxos算法是基于消息传递通讯模型的。

算法描述

三种角色

在 Paxos 算法中有三种角色,分别具有三种不同的行为。但很多时候,一个进程可能同时充当着多种角色。

  • Proposer:提案(Proposal)的提议者。在一个集群中,提议者(Proposer)也是可能存在多个的,不同的提议者(Proposer)会提出不同的提案。
  • Acceptor:提案的表决者,级是否 accept 该提案。只有半数以上的 Acceptor 接受了某提案,那么该提案者被认定为“选定”。
  • Learners:提案的学习者。当提案被选定时,其要执行提案内容。
Paxos算法的一致性

Paxos 算法的一致性主要体现在以下几点:

  • 没有提案被提出,则不会有提案被选定。
  • 每个提议者在提出提案时,都会首先获取到一个具有全局唯一性的、递增的提案编号 N,即在整个集群中唯一的编号N,然后将该编号赋予其要提出的提案。
  • 每个表决者在 accept 某提案后,会将该提案的编号 N 记录在本地,这样每个表决者中保存的已经被 accept 的提案中会存在一个编号最大的提案,其编号假设为 maxN。每个表决者仅会 accept 编号大于自己本地 maxN 的提案。
  • 在众多提案中最终只能有一个提案被选定。
  • 一旦一个提案被选定,则其它服务器会主动同步(Learn)该提案到本地。
算法过程描述

Paxos算法的执行过程划分为两个阶段:准备阶段prepare接受阶段accept
在这里插入图片描述

prepare阶段
  • 提议者(Proposer)准备提交一个编号为 N 的提议,于是其首先向所有表决者(Acceptor)发送 prepare(N) 请求,用于试探集群是否支持该编号的提议。
  • 每个表决者(Acceptor)中都保存着自己曾经 accept 过的提议中最大的编号 maxN。当一个表决者接收到其它主机发送来的 prepare(N) 请求时,其会比较 N 与 maxN 的值。有以下几种情况:
    1)若 N 小于 maxN,则说明该提议已过时,当前表决者采取不回应或者回应 Error 的方式来拒绝该 prepare 请求;
    2)若 N 大于 maxN,则说明该提议是可以接受的,当前表决者会首先将该 N 记录下来,并将其曾经已经 accept 的编号最大的提案 Proposal(myid, maxN, value) 反馈给提议者,以向提议者展示自己支持的提案意愿。其中第一个参数 myid 表示表决者 Acceptor 的标识id,第二个参数表示其曾接受的提案的最大编号 maxN,第三个参数表示该提案的真正内容 value。当然,若当前表决者还未曾 accept 过任何提议,则会将 Proposal(myid, null, null)反馈给提议者。
    3)在 prepare 阶段 N 不可能等于 maxN,这是由 N 的生成机制决定的。要获得 N 的值,其必定会在原来数值的基础上采用同步锁方式增一。
accept阶段
  • 当提议者(Proposer)发出 prepare(N) 后,若收到了超过半数的表决者(Acceptor)的反馈,那么该提议者就会将其真正的提案 Proposal(myid, N, value) 发送给所有的表决者。
  • 当表决者(Acceptor)接收到提议者发送的 Proposal(myid, maxN, value) 提案后,会再次拿出自己曾经 accept 过的提议中的最大编号 maxN,或曾经记录下的 prepare 的最大编号,让 N 与它们进行比较。若 N 大于等于 这两个编号,则当前表决者 accept 该提案,并反馈给提议者。若 N 小于这两个编号,则表决者采取不回应或回应 Error 的方式来拒绝该提议。
  • 若提议者没有接收到超半数的表决者的 accept 反馈,则重新进入 prepare 阶段,递增提案后,重新提出 prepare 请求。若提议者接收到的反馈数量超过了半数,则其会向外广播两类信息:
    1)向曾 accept 其提案的表决者发送“可执行数据同步信号”,即让它们执行其曾接收到的提案;
    2)向未曾向其发送 accept 反馈的表决者发送“提案 + 可执行数据同步信号”,即让它们接受到该提案后马上执行。

Paxos算法的活锁问题

  • 前面所述的 Paxos 算法在实际工程应用过程中,根据不同的实际需求存在诸多不便之处,所以也就出现了很多对于基本 Paxos 算法的优化算法,以对 Paxos 算法进行改进,例如:Multi Paxos、Fast Paxos、EPaxos。
  • 例如,Paxos 算法存在“活锁问题”,Fast Paxos 算法对 Paxos 算法进行了改进:其只允许一个进程处理写请求,解决了活锁问题。
  • Fast Paxos 算法只允许一个进程提交提案,即其具体对 N 的唯一操作权,该方式解决了“活锁问题”。
  • 活锁指的是任务或者执行者没有被阻塞,由于某些条件没有满足,导致一直重复尝试—失败—尝试—失败的过程。处于活锁的实体是在不断的改变状态,活锁有可能自行解开。

ZAB协议

ZAB协议简介

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

ZAB与Paxos的关系

  • ZAB协议是 Fast Paxos 算法是一种工业实现算法,但两者的设计目标不太一样。ZAB 协议主要用于构建一个高可用的分布式数据主备系统。例如,Leader挂了,马上就可以选举出一个新的 Leader。而 Paxos 算法则是用于构建一个分布式一致性状态机系统,确保系统中各个节点的状态都是一致的。
  • 另外,ZAB还使用 Google 的 Chubby 算法作为分布式锁的实现,而 Google 的 Chubby 也是 Paxos 算法的应用。

三类角色

为了避免 Zookeeper 的单点问题,Zookeeper 也是以集群的形式出现的。Zookeeper集群中的角色主要有以下三类:

  • Leader:集群中事务请求的唯一处理者,也可以处理读请求,其还负责进行投票及决议。
  • Follower:可以接收客户端读/写请求,可以直接处理并响应读请求;其不会处理事务请求,只会将客户端事务请求转发给Leader来处理。对Leader发起的事务提案具有表决权;同步Leader中的事务处理结果。当 Leader 宕机后,其还具有新 Leader 的选举权与被选举权。
  • Observer:可以理解为不参与Leader选举的 Follower,在Leader选举过程中没有选举权与被选举权;同时,对于Leader的提案没有表决权。用于协助 Follower处理更多的客户端读请求,提升对读请求的处理效率。

一般为了增大读请求的吞吐量,需要增加 Observe,而不增加 Follower,这样做既不影响写请求,也不会影响 Leader 的选举的效率。
写请求,Leader会问 Follower 同不同意写,但是不会问Observer。所以Follower越少,写请求效率越高。
场景1:1个处长,3个科长,90个临时工。如果处长挂了,3个科长中只需要有人获得2票,新的处长就产生了。场景2:1个处长,100个科长。如果处长挂了,要在100个科长中选出新的处长,就相对比较复杂了。

这三类角色在不同的情况下又有一些不同的叫法:

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

三个数据

在ZAB中有三个很重要的数据

  • zxid:64位长度的Long,高32位是epoch,低32位是xid。zxid = epoch + xid
  • epoch:(美[ˈepək])时期,纪元,世,新时代。类似于古代的 年号,该值每次递增+1
  • xid:事务id,流水号,该值每次递增+1

三种模式

ZAB协议中对 Zookeeper Server 的状态描述有三种模式,这三种模式并没有十分明显的界限,它们相互交织在一起。

  • 恢复模式:在集群启动过程中,或Leader崩溃后,系统都需要进入恢复模式,以恢复系统对外提供服务的能力。其包含两个重要阶段:Leader 的选举阶段,与初始化同步阶段
  • 广播模式:初始化广播,与更新广播
  • 同步模式:初始化同步,与更新同步

四种状态

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

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

同步模式与广播模式

初始化广播
  • 前面我们说过,恢复模式具有两个阶段:Leader选举与初始化同步(广播)。当完成Leader选举后,此时的 Leader 还是一个准 Leader,其要经过初始化同步后才能变为真正的 Leader

在这里插入图片描述
具体过程如下:

  • 为了保证 Leader 向 Learner 发送提案的有序,Leader 会为每一个 Learner 服务器准备一个队列;
  • Leader 将这些没有被各个Learner 同步的事务封装为 Proposal;
  • Leader 将这些 Proposal 逐条发给各个Learner,并在每一个 Proposal 后都紧跟一个 COMMIT 消息,表示该事务已经被提交,Learner 可以直接接受并执行;
  • Learner 接收到来自于 Leader 的 Proposal,并将其更新到本地;
  • 当 Follower 更新成功后,会向准 Leader 发送 ACK 信息;
  • Leader 服务器在收到该来自 Follower 的 ACK 后就会将该 Follower 加入到真正可用的 Follower 列表。没有反馈 ACK,或者反馈了但 Leader 没有收到的 Follower,Leader 不会将其加入到 Follower 列表。
消息广播算法
  • 在集群中已经有过半的 Follower 完成了初始化状态同步,那么整个 Zookeeper 集群就进入到了正常工作模式了。

在这里插入图片描述
如果集群中的其他节点收到客户端的事务请求,那么这些 Learner 会将请求转发给 Leader 服务器。然后再执行如下的具体过程:

  • Leader 接收到事务请求后,为事务赋予一个全局唯一的 64 位自增 id,即 zxid,通过 zxid 的大小比较即可实现事务的有序性管理,然后将事务封装为一个 Proposal;
  • Leader 根据 Follower 列表获取到所有 Follower,然后再将 Proposal 通过这些 Follower 的队列将提案发送给各个 Follower;
  • 当 Follower 接收到提案后,会先将提案的 zxid 与本地记录的事务日志中的最大的 zxid 进行比较。若当前提案的 zxid 大于最大 zxid,则将当前提案记录到本地事务日志中,并向 Leader 返回一个 ACK;
  • 当 Leader 接收到过半的 ACKs 后,Leader 就会向所有的 Follower 的队列发送 COMMIT 消息,向所有 Observer 的队列发送 Proposal;
  • 当 Follower 收到 COMMIT 消息后,就会将日志中的事务正式更新到本地。当 Observer 收到 Proposal 后,会直接将事务更新到本地。
Observer 的数量问题
  • Observer 数量一般与 Follower 数量相同。并不是 Observer 越多越好,因为 Observer 数量的增多虽不会增加事务操作压力,但其需要从 Leader 同步数据,Observer 同步数据的时间是小于等于 Follower 同步数据的时间的。当 Follower 同步数据完成,Leader 的 Observer 列表中的 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 间的心跳来维护的。
  • Leader中对于Follower也同样存在两个列表:all与service。其功能与Observer的相似。但不同点是,若 Leader 收到的 Follower 同步完成的 ACK 数量没有过半,则认为同步失败,会重新进行广播,让 Follower 重新进行同步。

恢复模式的三个原则

  • 当集群正在启动过程中,或 Leader 与超过半数的主机断连后,集群就进入了恢复模式。对于要恢复的数据状态需要遵循两个原则。
Leader的主动出让原则
  • 若集群中 Leader 收到的 Follower 心跳数量没有过半,此时 Leader 会自认为自己与集群的连接已经出现了问题,其会主动修改自己的状态为 LOOKING,去查找新的 Leader。为了防止集群出现脑裂。
  • 而其它 Server 由于有过半的主机认为已经丢失了 Leader,所以它们会发起新的 Leader 选举,选出一个新的 Leader。
已被处理的消息不能丢
  • 当 Leader 收到超过半数 Follower 的 ACKs后,就向各个 Follower 广播 COMMIT 消息,批准各个 Server 执行该写操作事务。当各个 Server 在接收到 Leader 的 COMMIT 消息后,就会在本地执行该写操作,然后会向客户端响应写操作成功。
  • 但是如果在非全部 Follower 收到 COMMIT 消息之前 Leader 就挂了,这将导致一种后果:部分 Server 已经执行了该事务,而部分 Server 尚未收到 COMMIT 消息,所以其并没有执行该事务。当新的 Leader 被选举出,集群经过恢复模式后需要保证所有 Server 上都执行了那些已经被部分 Server 执行过的事务。
被丢弃的消息不能再现
  • 当 Leader 接收到事务请求并生成了 Proposal,但还未向任何 Follower 发送时就挂了,因此,其他 Follower根本就不知道该 Proposal 的存在。当新的 Leader 选举出来,整个集群进入正常服务状态后,之前挂了的 Leader 主机重新启动并注册成为了 Follower。若那个别人根本不知道的 Proposal 还保留在那个主机,那么其数据就会比其它主机多出了内容,导致整个系统状态的不一致。所以,该 Proposal 应该被丢弃。类似这样应该被丢弃的事务,是不能再次出现在集群中的,应该被清除。

简单来说就是要所有节点的消息以当前 Leader 为准,Leader 中多出来的信息需要被所有节点同步,Leader 中没有的消息,需要从有多于消息的节点(恢复前的Leader)删除。

Leader选举

Leader选举中的基本概念
  • myid:也称为serverId,这是 zk 集群中服务器的唯一标识,称为 myid。例如,有三个 zk 服务器,那么编号分别为1、2、3
  • 逻辑时钟:Logical clock,是一个整型数,该概念在选举时称为Logical clock,而在选举结束后称为 epoch。即 epoch 与Logical clock 是同一个值,在不同情况下的不同名称。
  • zk状态:zk 集群中的每一台主机,在不同的阶段会处于不同的状态。每一台主机具有四种状态:LOOKING(选举状态)FOLLOWING(跟随状态)OBSERVING(观察状态)LEADING(领导状态)
Leader选举算法

在集群启动过程中的 Leader 选举过程(算法)与 Leader 断连后的 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规则如下:
* 优先检查 zxid,zxid 比较大的服务器优先作为 Leader;
* 如果 zxid 相同,那么就比较 myid,myid 较大的服务器作为 Leader 服务器。

  对于 Server1 而言,它的投票是 (1, 0),接收 Server2 的投票为 (2, 0)。其首先会比较两者的 zxid,均为0;再比较 myid,此时 Servr2 的 myid 最大,于是 Server1 更新自己的投票为 (2, 0),然后重新投票,对于 Server2 而言,其无需更新自己的投票, 只是再次向集群中所有主机发出一次投票信息即可。

  • 4、统计投票:每次投票后,服务器都会统计投票信息,判断是否已经有过半机器接受到相同的投票信息。对于 Server1、Server2 而言,都统计出集群中已经有两台主机接受了 (2, 0) 的投票信息,此时便认为已选出了新的 Leader,即 Server2;
  • 5、改变服务器状态:一旦确定了 Leader,每个服务器就会更新自己的状态,如果是 Follower,那么就变为 Following,如果是 Leader,就会变为 Leading;
  • 6、添加主机:在新的 Leader 选举出来后 Server3 启动,其想发出新一轮的选举。但由于当前集群中各个主机的状态并不是 Looking,而是各司其职的正常服务,所以其只能是以 Follower 的身份加入到集群中。
断连后的 Leader 选举

  在 Zookeeper 运行期间,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、Servrer2而言,都统计出集群中已经有两台主机接受了 (3, 333) 的投票信息,此时便认为已经选出了新的 Leader,即 Server3;
  • 6、改变服务器的状态:与启动时过程相同。一旦确定了 Leader,每个服务器就会更新自己的状态。Server1 变为 Following,Server3 变为 Leading;

CAP定理

简介

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

  • 一致性(C):分布式系统中多个主机之间是否能够保持数据一致的特性。即当系统数据发生更新操作后,各个主机中的数据仍然处于一致的状态。
  • 可用性(A):系统提供的服务必须一直处于可用的状态,即对于用户的每一个请求,系统总是可以在有限的时间内对用户做出响应。不同的系统的“有限时间”是不一样的,百度0.5秒,谷歌0.3秒给出千万级查询结果。
  • 分区容错性(P):分布式系统在遇到任何网络分区故障时,仍能够保证对外提供满足一致性和可用性的服务。

三二原则

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

  • 案例自己小结:在一个分布式系统中,假设系统正在进行数据同步,此时用户请求该系统。如果此时整个集群还能对外提供服务,即满足可用性,那么用户请求就有可能访问到某一台还没有同步数据的主机,造成数据的不一致,这种场景就是牺牲了CP,满足AP。如果为了满足系统数据的一致性,那么此时整个集群就不对外提供服务,即此时是不可硬,这种场景就是牺牲了AP,满足CP。

BASE理论

  • BASE 是 Basically Available(基本可用)、Soft state(软状态)和Eventually consistent(最终一致性)三个短语的简写。
  • BASE 理论的核心思想是:即使无法做到强一致性,但每个系统都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性
基本可用
  • 基本可用是指分布式系统在出现不可预知故障的时候,允许损失部分可用性。例如:损失响应时间,服务降级(淘宝双11期间不能修改地址,不能退换货)。
软状态
  • 软状态,是指允许系统数据存在的中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时。软状态,其实就是一种灰度状态,过渡状态。例如:做数据同步时。
最终一致性
  • 最终一致性强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。
  • 在没有发生故障的前提下,数据达到一致状态的时间延迟,取决于网络延迟,系统负载和数据复制方案设计等因素。

ZK与CP

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

Zookeeper的安装与集群搭建

安装单机Zookeeper

准备工作

  • 安装包下载:可以在 Zookeeper 官网:http://zookeeper.apache.org/ 去下载,可以是使用国内镜像地址下载
wget http://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.4.14/zookeeper-3.4.14.tar.gz

安装配置zk

# 解压缩
tar -xzvf /usr/tools/zookeeper-3.4.14.tar.gz -C /usr/apps/
# 创建软链接
ln -s /usr/apps/zookeeper-3.4.14/ /usr/apps/zk

在这里插入图片描述

  • 复制配置文件:复制 Zookeeper 安装目录下的 conf 目录中的 zoo_sample.cfg 文件,并命名为 zoo.cfg
    在这里插入图片描述
  • 修改配置文件:
    在这里插入图片描述
  • 新建数据存放目录:
mkdir -p /usr/data/zookeeper
  • 注册 bin 目录:vim /etc/profile
    在这里插入图片描述
  • 重新加载 profile 文件:
source /etc/profile

配置说明

  • tickTimeClient-Server通信心跳时间
    Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳。tickTime以毫秒为单位。默认设置:tickTime=2000。
  • initLimitLeader-Follower初始通信时限
    集群中的follower服务器(F)与leader服务器(L)之间初始连接时能容忍的最多心跳数(tickTime的数量)。默认设置:initLimit=10。
  • syncLimitLeader-Follower同步通信时限
    集群中的follower服务器与leader服务器之间请求和应答之间能容忍的最多心跳数(tickTime的数量)。默认设置:syncLimit=5。
  • dataDir数据文件目录
    Zookeeper保存数据的目录,默认情况下,Zookeeper将写数据的日志文件也保存在这个目录里。默认设置:dataDir=/temp/zookeeper。
  • clientPort客户端连接端口
    客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求。默认设置:clientPort=2181。
  • 服务器名称与地址集群信息(服务器编号,服务器地址,LF通信端口,选举端口)
    这个配置项的书写格式比较特殊,规则如下:server.N=YYY:A:B。例如:
server.1=itcast05:2888:3888
server.2=itcast06:2888:3888
server.3=itcast07:2888:3888
# 2888为连接端口号,用于zookeeper服务器之间及通讯,3888为选举端口

操作Zookeeper

  • 开启 zk:
    在这里插入图片描述
  • 查看状态:
    在这里插入图片描述
  • 重启 zk:
    在这里插入图片描述
  • 停止 zk:
    在这里插入图片描述

搭建Zookeeper集群

  • 下面要搭建一个由四台 zk 构成的 zk 集群,其中一台为 Leader,两台 Follower,一台 Observer
  • 主机:
server.1=192.168.254.128
server.2=192.168.254.130
server.3=192.168.254.132
server.4=192.168.254.129			Observer

克隆并配置第一台主机

  • 修改zoo.cfg:在 zoo.cfg 文件中添加 zk 集群节点列表
server.1=192.168.254.128:2888:3888
server.2=192.168.254.130:2888:3888
server.3=192.168.254.132:2888:3888
server.4=192.168.254.129:2888:3888:observer

在这里插入图片描述

  • 删除无效数据
rm -rf /usr/data/zookeeper/*
  • 创建 myid文件:在 /usr/data/zookeeper 目录中创建当前主机编号的 myid 文件,该主机编号要与 zoo.cfg 文件中设置的编号一致:
echo 1 > /usr/data/zookeeper/myid

在这里插入图片描述

克隆并配置另两台主机

与第一台主机配置类似:

* 修改 zoo.cfg
* 删除无效数据
* 创建 myid文件

在这里插入图片描述
在这里插入图片描述

克隆并配置第四台主机

第四台主机即为 Observer 的主机,其他的配置都类似,不同的是:
在这里插入图片描述
在这里插入图片描述

启动zk集群

  • 首先关闭各个主机的防火墙
systemctl stop firewalld(默认)
systemctl disable firewalld.service(设置开机不启动)
  • 使用 zkServer.sh start命令,逐个启动每一个 Zookeeper 节点主机。
  • 集群状态查看:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 使用命令echo stat | nc IP 2181查看节点状态:
    在这里插入图片描述
    在这里插入图片描述

高可用集群的容灾

服务器数量的奇数与偶数

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

容灾设计方案

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

在生产环境下,三机房部署是最常见的、容灾性最好的部署方案。假定 zk 集群中机器总数(不含Observer)为N,三个机房中部署的机器数量分别为 N1、N2、N3。

  • A机房——N1 的值:N1 = (N - 1) / 2,即要保证第一机房中具有刚不到半数的主机。假设N=15台,则N1 = (15 - 1) / 2 = 7。
  • B机房——N2 的值:N2 的值是一个取值范围,1 ~ (N - N1) / 2。即:1 ~ (15 - 7)/2 = 1 ~ 4,假设 N2 = 3。
  • C机房——N3 的值:N3 = N - N1 - N2 = 15 - 7 - 3 = 5。

容灾能力分析:假设A机房挂了,则剩下的B机房、C机房的主机加起来还有 8 台,超过总数一半了,集群还能正常运行。同理,当 B 机房挂了,还有 12 台主机正常,超过总数一半了;当 C 机房挂了,还有 10 台主机正常,超过总数一半了;这样都能保证集群正常运行。

双机房部署

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

扩容与缩容

水平扩展对于提高系统服务能力,是一种非常重要的方式,但 zk 对于水平扩容与缩容做的并不完美,主机数量的变化需要修改配置文件后整个集群进行重启。集群重启的方式有两种:整体重启和部分重启。

整体重启

整体重启指将整个集群停止,然后更新所有主机的配置后,再重启集群。该方式会使集群停止对外服务,所以该方式慎用。

部分重启

部分重启指每次重启一小部分主机(一般是1/3),注意不能多于半数,因为重启的主机过半,则意味着剩余主机就不会过半,那么这些剩余的主机将无法产生合法投票结果,即若出现宕机无法进行选举,不宕机无法提供写服务。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

讲文明的喜羊羊拒绝pua

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值