ZooKeeper一致性原理

原文链接:https://www.cnblogs.com/sunddenly/p/4138580.html

一、ZooKeeper 的实现

1.1 ZooKeeper处理单点故障

我们知道可以通过ZooKeeper对分布式系统进行Master选举,来解决分布式系统的单点故障,如图所示。

image-20200316114744867

那么我们继续分析一下,ZooKeeper通过Master选举来帮助分布式系统解决单点故障,保证该系统中每时每刻只有一个Master为分布式系统提供服务。也就是说分布式的单点问题交给了ZooKeeper来处理,不知道大家此时有没有发现一个问题——”故障转移到了ZooKeeper身上”。大家看一下图就会发现,如果我们的ZooKeeper只用一台机器来提供服务,若这台机器挂了,那么该分布式系统就直接变成双Master模式了,那么我们在分布式系统中引入ZooKeeper也就失去了意义。那么这也就意味着,ZooKeeper在其实现的过程中要做一些可用性和恢复性的保证。这样才能让我们放心的以ZooKeeper为起点来构建我们的分布式系统,来达到节省成本和减少bug的目的。

1.2 ZooKeeper运行模式

ZooKeeper服务有两种不同的运行模式。一种是”独立模式”(standalone mode),即只有一个ZooKeeper服务器。这种模式较为简单,比较适合于测试环境,甚至可以在单元测试中采用,但是不能保证高可用性和恢复性。在生产环境中的ZooKeeper通常以”复制模式”(replicated mode)运行于一个计算机集群上,这个计算机集群被称为一个”集合体”(ensemble)。

图 1.2 ZooKeeper集群

img

ZooKeeper通过复制来实现高可用性,只要集合体中半数以上的机器处于可用状态,它就能够提供服务。例如,在一个有5个节点的集合体中,每个Follower节点的数据都是Leader节点数据的副本,也就是说我们的每个节点的数据视图都是一样的,这样就可以有五个节点提供ZooKeeper服务。并且集合体中任意2台机器出现故障,都可以保证服务继续,因为剩下的3台机器超过了半数。

注意,6个节点的集合体也只能够容忍2台机器出现故障,因为如果3台机器出现故障,剩下的3台机器没有超过集合体的半数。出于这个原因,一个集合体通常包含奇数台机器。

从概念上来说,ZooKeeper它所做的就是确保对Znode树的每一个修改都会被复制到集合体中超过半数的机器上。如果少于半数的机器出现故障,则最少有一台机器会保存最新的状态,那么这台机器就是我们的Leader。其余的副本最终也会更新到这个状态。如果Leader挂了,由于其他机器保存了Leader的副本,那就可以从中选出一台机器作为新的Leader继续提供服务。

1.3 ZooKeeper的读写机制

(1) 概述

ZooKeeper核心思想是,提供一个非锁机制的Wait Free的用于分布式系统同步的核心服务。提供简单的文件创建、读写操作接口,其系统核心本身对文件读写并不提供加锁互斥的服务,但是提供基于版本比对的更新操作,客户端可以基于此自己实现加锁逻辑。如下图1.3所示。

图 1.3 Using versions to prevent inconsistencies due to concurrent updates

img

(2) ZK集群服务

Zookeeper是一个由多个Server组成的集群,该集群有一个Leader,多个Follower。客户端可以连接任意ZooKeeper服务节点来读写数据,如下图1.4所示。

图 1.4 ZooKeeper集群服务

img

ZK集群中每个Server,都保存一份数据副本。Zookeeper使用简单的同步策略,通过以下两条基本保证来实现数据的一致性:

① 全局串行化所有的写操作

② 保证同一客户端的指令被FIFO执行(以及消息通知的FIFO)

所有的读请求由Zk Server 本地响应,所有的更新请求将转发给Leader,由Leader实施。

(3) ZK组件

ZK组件,如图1.5所示。ZK组件除了请求处理器(Request Processor)以外,组成ZK服务的每一个Server会复制这些组件的副本。

图 ZooKeeper组件图