1. Zookeeper可用性保证

在前面的文章中,我们已经知道业务系统可以通过zookeeper针对一个节点创建顺序子节点来进行系统的集群Leader选举,保证每时每刻只有一个Leader,但是此时系统的单点故障就转移到了Zookeeper身上,所以Zookeeper需要提供高可用的服务。

Zookeeper通过复制来实现系统的高可用性,生产环境中一般使用Zookeeper集群,Zookeeper保证每个队Znode树的修改,都会被复制到集合体超过半数的机器上。 所以集群中只要有超过半数的Zookeeper节点仍可用,则保证系统是可用的。

1.1 概述

Zookeeper保证可用性的核心思想是,提供一个非锁机制的用于分布式系统同步的核心服务,提供简单的文件创建、读写操作接口,只提供基于版本对比的更新操作,即每次更新客户端根据版本号来校验是否成功。

1.2 Zk集群服务

Zookeeper是一个由一个Leader和多个Follower组成的集群,客户端可以连接任意的Zookeeper节点来读写数据,所有杜青丘有ZKServer本地相应。所有更新请求将转发给Leader,由Leader实施。
Zk集群中每个Server,都保存着一份数据副本,Zookeeper使用简单的同步策略,通过以下两条基本保证来实现数据的一致性:

  1. 全局串行化所有的写操作
  2. 保证统一客户端的指令被FIFO执行(以及消息通知)

1.3 Zookeeper组件

ReplicatedDatabase是一个内存数据库,包含了整个data tree,为了恢复,更新会先被记录到磁盘,然后再写入数据库。

zookeeper 做高可用_大数据

上图是原文的图,不知道准确与否,图中read request不走RequestProcessor,让我比较疑惑

1.4 Zookeeper性能

2. Zookeeper与CAP

2.1 CAP理论概述

分布式系统中存在CAP理论:

  1. C:Consistency 一致性,数据一致更新,所有数据变动都是同步的
  2. A:Availability 可用性,系统具有良好的响应性能
  3. P:Partition tolerance 分区容错性,以实际效果而言,系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择,也就是说无论任何消息丢失,系统都可用。

该理论已被证明:任何分布式系统只可同时满足两点,无法三者兼顾,所以应该根据实际业务场景进行适当取舍。
其中分区容错性在分布式系统中一般是不可避免的,所以可认为P一定存在,系统需要在CA中进行取舍。

2.2 一致性分类

一致性是指从系统外部读取系统内部的数据时,数据变动在系统各节点间是同步的,根据一致性强弱程度的不同,可以将一致性级别认为如下几种:

  1. 强一致性
    任何时刻,任何用户都能读到最新一次成功更新的数据
  2. 单调一致性
    任何时刻,任何用户一旦读到某个数据在某次更新后的值,就不会再读到比这个值梗旧的值,也就是说,可获取数据顺序必是单调递增的。
  3. 会话一致性
    任何用户在某次会话中读到某数据更新后的值,本次回话就不会读到比这个更旧的值,相当于在单调一致性上进一步放松约束,只保证单个用户在单个会话中的一致性
  4. 最终一致性
    用户只能读到某次更新后的值,但系统保证数据将最终达到完全一致的状态,只是所需时间不能保证
  5. 弱一致性
    用户无法再确定时间内读到最新更新的值

2.3 Zookeeper与CAP理论

Zookeeper在一致性上有许多说法,我个人认为是单调一致性。它在分区容错性和可用性上也做了一定的折中,Zookeeper主要从以下几点保证了数据的一致性:

  • 顺序一致性
    来自任意客户端的更新,都会按照其发送顺序被提交,若某客户端将Node1更新为a再更新为b,name所有客户端都是先看到a再看到b
  • 原子性
    每个更新要么成功,要么失败。意味着如果一个更新失败,则不会有客户端看到这个更新的结果。
  • 单一系统镜像
    一个客户端连接任何一个服务器,看到的系统状态都不会比原来的更老。
    当一台服务器出现故障,所有滞后于故障服务器的服务器都不会接受属于该客户端的连接请求,除非这些服务器状态同步到故障服务器同一状态。
  • 持久性
    成功的更新会被持久化到磁盘,不会因为故障丢失

3. Zookeeper原理概述

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

  1. 恢复模式
    服务启动或者领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,并且大多数Server都完成了和Leader的状态同步后,恢复模式就结束了。
  2. 广播模式 恢复模式结束后,进入广播模式。这是如果一个Server加入Zookeeper服务中,他会在恢复模式下启动,发现Leader并与Leader进行状态同步,同步结束后,它也会参与消息广播,Zookeeper服务移植维持广播(Broadcast)状态,直到Leader崩溃了或者Leader失去了大部分Follwers支持。
    在广播模式Zookeeper Server会接受client请求,所有的写请求都被转发给Leader,再由领导者将更新广播给Follower。当半数以上的Follower已经完成持久化后,Leader才会提交这个更新,然后客户端才会收到一个更新成功的相应。

下图比较好,拉过来看一下

zookeeper 做高可用_数据库_02

3.1 广播模式

广播模式类似与一个简单的两阶段提交:Leader发起一个请求,收集选票,并且最终提交 下图演示了我们协议的消息流程。Follower要么确认Leader的提议,要么丢弃Leader的提议,没有拒绝选项,所以不需要等待所有机器的回应,只要有指定数量的机器确认了提议,该提议就会被通过

zookeeper 做高可用_zookeeper 做高可用_03


广播协议在所有的通讯过程中使用TCP的FIFO信道,使保持有序性变得非常容易。通过FIFO信道,消息被有序的deliver,只要收到的消息已被处理,其顺序就被保存下来。

Leader会广播已经被deliver的Proposal消息,在广播前会分配给Proposal一个单调递增的id,称为zxid。zab把Proposal封装到消息中,并添加到只想Follower的输出队列中,通过FIFO信道发送到Follower。

当Follower收到一个Proposal时,会将其写入到磁盘中,一旦写入成功,Follower会发送一个ACK给Leader,Leader收到了指定数量的ACK时,Leader将广播commit消息,并在本地deliver该消息,当收到Leader发来的commit消息时,Follower也会提交该消息

3.2 恢复模式

3.2.1 概述

Leader故障或者失去了指定数量的Follower支持时,Zab会进入恢复模式,重新选举一个Leader,恢复模式需要注意以下几点

  • Leader选举不仅能够让Leader得知它是Leader,还要有指定数量的Follower同意该决议。
  • 如果选举阶段发生错误,那么选举不会继续,最终会发生超时,重新进行选举

恢复阶段的复杂部分是在一个给定的时间内,提议冲突的绝对数量,可配置默认为1000,为了使该协议及时在Leader故障的情况下也能工作,需要做出如下两条保证:

  1. 我们绝不能遗忘已经被deliver的消息,若一条消息在一台机器上被deliver,name消息必须在每台机器上deliver
  2. 我们必须丢弃已经被skip的消息
3.2.2 保证示例

第一条的情况: Leader发送了commit消息,但是commit消息到达任何其他机器之前,Leader发生了故障,只有Leader自己收到了commit消息,所以只有leader自己的client看到了更新成功,所以第一条保证需要将此commit消息deliver到所有机器,是client看到一个一致性的数据视图 第二条的情况 Leader发送了Propose消息,消息到达任何其他机器之前,Leader发生了故障,所以Leader恢复时,需要丢弃调该Propose

3.2.3 保证的实现
  1. 第一条的实现:
    所有的正确启动的Servers,将会成为Leader或者跟随一个Leader。Leader能够确保它的Followers看到所有的提议,并deliver所有已经deliver的消息。
    通过将新连接上的Follower所没有见过的所有PROPOSAL进行排队,并之后对该Proposals的COMMIT消息进行排队,直到最后一个COMMIT消息。在所有这样的消息已经排好队之后,Leader将会把Follower加入到广播列表,以便今后的提议和确认。
    (后面的说法原博感觉有些问题,不再使用)
    zookeeper在deliver commit消息时,会先发送给follower,当发送给指定数量的follower并收到回复时,leader才会对本地进行commit,这样会解决第一个情景的问题。
  2. 第二条的实现
    第二条比较简单,在Zookeeper中,Zxid使用64位数字组成的,低32位用作简单计数器,高32位是一个epoch。每当新Leader接管它时,将获取日志中最大的epoch,新leader的epoch位+1,counter位设置0,用epoch标记领导关系的改变。 这个方案的优点是,我们可以skip一个失败的领导者的实例,加速并简化恢复过程,如果一台宕机的Server重启,并带有未发布的Propersal,name先前的未发布的所有提议将永不会被deliver,新的Leader会告诉它清除这些提议。