zookeeper1 - zookeeper简介

2019/04/28

zookeeper1 - zookeeper简介

本篇博文是对zookeeper的基本工作和逻辑组成进行说明,通过本文可以了解到:

  • zookeeper的作用
  • zookeeper的构成
  • zookeeper的实现过程

博文纯属个人理解,有错误之处还请指正。

1 2 3


1 zookeeper简介

我的理解zookeeper是一种负载均衡实现,或者说负载均衡中(nginx)用到了zookeeper技术。

zookeeper是协调客户端访问分布式服务的一种协作框架。zookeeper存储在服务器集群上,用于服务器自身资源的协调,通过稳健的同步技术维护共享数据。

zookeeper提供的服务:

  • 命名服务 - 为集群节点(一台服务器)命名,唯一id;
  • 配置管理 - 集群节点的系统配置信息;
  • 集群管理 - 集群删减节点;
  • 选举算法 - 选举leader;
  • 锁定和同步服务 - 写入阻塞;
  • 高度可靠的数据注册表 - 挂掉部分节点仍能正常工作。

2 zookeeper组成

zk

如图,是一个zookeeper集群的调用过程,服务器集群由zookeeper管理,即zookeeper集群;client访问请求服务器由zookeeper管理。

整个服务主要由四部分组成:

角色 分工 数量
client客户端 请求发起方 不限
zookeeper集群    
leader领导者 负责提议,更新系统状态 不限
observer观察者 接受用户读写请求,写转发给leader,读直接返回(选主过程不参加投票) 不限
follower跟随者 接受用户读写请求,写转发给leader,读直接返回(选主过程参加投票) 不限

说明:

  1. client(客户端): 用户
  2. server(服务器): 集群节点
  3. leader: 集群中选举leader
  4. follower: 跟随leader指令的
  5. observer: 观察者
  6. Ensemble(ZooKeeper服务器组): 集群

1 zookeeper组成

上述是整个zookeeper圈的组成部分,而zookeeper架构则主要包括zookeeper与服务器集群两部分。

1 zone

ZooKeeper数据模型采用的是层次命名空间,类似于树或者目录格式:

zknamespace

树中的节点叫做znode,如图一个znode节点包括四个部分:

struct Znode {
  data    //Znode存储的数据信息。
  ACl     //记录Znode的访问权限,即哪些人或哪些IP可以访问本节点。
  stat    //包含Znode的各种元数据,比如事务ID、版本号、时间戳、大小等等。
  child   // 当前节点的子节点引用
}

znode

说明:

  1. Zookeeper是为读多写少的场景所设计。Znode并不是用来存储大规模业务数据,而是用于存储少量的状态和配置信息,每个节点的数据最大不能超过1MB。
  2. zookeeper有专门的API对节点增删改查;

之前对znode一直不明白,觉得znode存放的数据一定是client或者server的信息,但是Znode其实就是一个结构体定义,就是一个class,那么存放什么都是自己去设计的。

2 一些补充

  1. 服务器数目奇数个, 故障过半原则,偶数和奇数的作用是一样的。
  2. 存储在znode中的数据总量是数据长度。你最多可以存储1MB的数据。
  3. Observer可以接受客户端连接,将写请求转发给leader,但observer不参加投票过程,只同步leader的状态,observer的目的是为了扩展系统,提高读取速度
  4. Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议。
  5. 为了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。
  6. 每个Server在工作过程中有三种状态:

     LOOKING:当前Server不知道leader是谁,正在搜寻     LEADING:当前Server即为选举出来的leader     FOLLOWING:leader已经选举出来,当前Server与之同步
    

2 zookeeper工作流

一句话:

client可以通过server创建znode,删除znode,写znode,读znode,设置监视等等。简而言之,客户端通过服务端来获取到zookeeper提供的服务。

zookeeper服务器就是代表的服务器集群节点,客户端调用服务时,服务器节点会在zookeeper上创建一个znode节点,客户端调用结束,节点删除(临时节点)

具体操作:

  1. 写操作只有leader能够执行
  2. 读任意
操作 描述
写入(write) 写请求转发给leader,leader将写入请求转发到所有znode,并等待znode的回复。如果一半的znode回复,则写入过程完成。
读取(read) 连接到的znode直接返回
复制数据库(replicated database) 它用于在zookeeper中存储数据。每个znode都有自己的数据库,每个znode在一致性的帮助下每次都有相同的数据。

通过Follower/Observer进行写操作流程如下图所示,Follower/Observer均可接受写请求,但不能直接处理,而需要将写请求转发给Leader处理.

其中leader写入成功后,会通知znodes,半数回复,写入成功。

work_flow

3 知识点总结

1 watch机制(客户端设置)

Znode的增、删、改将会触发watch所对应的操作,ZooKeeper将会向客户端发送且仅发送一条通知,因为watch只能被触发一次,这样可以减少网络流量。

API实现:

# 数据
watch(data watches):getData和exists负责设置数据watch

#孩子
watch(child watches):getChildren负责设置孩子watch

程序总是需要配置的,如果程序分散部署在多台机器上,要逐个改变配置就变得困难。现在把这些配置全部放到zookeeper上去,保存在 Zookeeper 的某个目录节点中,然后所有相关应用程序对这个目录节点进行监听,一旦配置信息发生变化,每个应用程序就会收到 Zookeeper 的通知,然后从 Zookeeper 获取新的配置信息应用到系统中就好

watch

2 zookeeper的CAP原则

1、 分区容错 Partition tolerance

系统在时限内达成数据一致性;

服务器通信失败;

2、 一致性 Consistency

在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)

写操作之后的读操作,必须返回该值;

3、 可用性 Availability

在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)

可用性 和 一致性的矛盾

一致性和可用性,为什么不可能同时成立?答案很简单,因为可能通信失败(即出现分区容错)。

G1/G2是两个服务器,如果保证 G2 的一致性,那么 G1 必须在写操作时,锁定 G2 的读操作和写操作。G2可用性不成立;

如果保证 G2 的可用性,那么势必不能锁定 G2,所以一致性不成立。

故G2 无法同时做到一致性和可用性。

3 Zookeeper 的保证

  • 更新请求顺序进行,来自同一个client的更新请求按其发送顺序依次执行
  • 数据更新原子性,一次数据更新要么成功,要么失败 (一致性)
  • 全局唯一数据视图,client无论连接到哪个server,数据视图都是一致的 (一致性)
  • 实时性,在一定事件范围内,client能读到最新数据 (可用性 + 一致性)

4 原子广播 & Zab协议(一致性算法)

ZooKeeper Atomic Broadcast(ZAB,zookeeper原子消息广播协议)

ZooKeeper并没有完全采用Paxos算法,而是使用了一种称为ZooKeeper Atomic Broadcast(ZAB,zookeeper原子消息广播协议)的协议作为其数据一致性的核心算法.

ZAB在Paxos算法上做了重要改造,和Paxos有着明显的不同。

ZAB协议的核心是定义了对于那些会改变Zookeeper服务器数据状态的事务请求的处理方式,即:所有事务请求必须由一个全局唯一的服务器来协调处理,这样的服务器被称为Leader服务器.

ZAB一些包括两种基本的模式:崩溃恢复和消息广播。

当整个服务框架启动过程中或Leader服务器出现网络中断、崩溃退出与重启等异常情况时,ZAB协议就会进入恢复模式并选举产生新的Leader服务器。当选举产生了新的Leader服务器,同时集群中已经有过半的机器与该Leader服务器完成了状态同步之后,ZAB协议就会退出恢复模式,状态同步时指数据同步,用来保证集群在过半的机器能够和Leader服务器的数据状态保持一致。

当集群中已经有过半的Follower服务器完成了和Leader服务器的状态同步,那么整个服务框架就可以进入消息广播模式,当一台同样遵守ZAB协议的服务器启动后加入到集群中,如果此时集群中已经存在一个Leader服务器在负责进行消息广播,那么加入的服务器就会自觉地进入数据恢复模式:找到Leader所在的服务器,并与其进行数据同步,然后一起参与到消息广播流程中去。Zookeeper只允许唯一的一个Leader服务器来进行事务请求的处理,Leader服务器在接收到客户端的事务请求后,会生成对应的事务提议并发起一轮广播协议,而如果集群中的其他机器收到客户端的事务请求后,那么这些非Leader服务器会首先将这个事务请求转发给Leader服务器。

当Leader服务器出现崩溃或者机器重启、集群中已经不存在过半的服务器与Leader服务器保持正常通信时,那么在重新开始新的一轮的原子广播事务操作之前,所有进程首先会使用崩溃恢复协议来使彼此到达一致状态,于是整个ZAB流程就会从消息广播模式进入到崩溃恢复模式。一个机器要成为新的Leader,必须获得过半机器的支持,同时由于每个机器都有可能会崩溃,因此,ZAB协议运行过程中,前后会出现多个Leader,并且每台机器也有可能会多次成为Leader,进入崩溃恢复模式后,只要集群中存在过半的服务器能够彼此进行正常通信,那么就可以产生一个新的Leader并再次进入消息广播模式。如一个由三台机器组成的ZAB服务,通常由一个Leader、2个Follower服务器组成,某一个时刻,加入其中一个Follower挂了,整个ZAB集群是不会中断服务的。

5 Zookeeper集群管理

所谓集群管理无在乎两点:是否有机器退出和加入、选举master。

对于第一点,所有机器约定在父目录GroupMembers下创建临时目录节点,然后监听父目录节点的子节点变化消息。一旦有机器挂掉,该机器与 zookeeper的连接断开,其所创建的临时目录节点被删除,所有其他机器都收到通知:某个兄弟目录被删除,于是,所有人都知道:它上船了。

新机器加入也是类似,所有机器收到通知:新兄弟目录加入,highcount又有了,对于第二点,我们稍微改变一下,所有机器创建临时顺序编号目录节点,每次选取编号最小的机器作为master就好。

zkservice

6 Zookeeper分布式锁

有了zookeeper的一致性文件系统,锁的问题变得容易。锁服务可以分为两类,一个是保持独占,另一个是控制时序。

1 保持独占

对于第一类,我们将zookeeper上的一个znode看作是一把锁,通过createznode的方式来实现。

所有客户端都去创建 /distribute_lock 节点,最终成功创建的那个客户端也即拥有了这把锁。用完删除掉自己创建的distribute_lock 节点就释放出锁。

2 控制时序

对于第二类, /distribute_lock 已经预先存在,所有客户端在它下面创建临时顺序编号目录节点,和选master一样,编号最小的获得锁,用完删除,依次方便。

lock

4 面试总结

1 如何保证主从节点的数据一致性?

为了保证主从节点的数据一致性,Zookeeper采用了ZAB协议,这种协议非常类似于一致性算法Paxos和Raft。

Zab协议既不是强一致性,也不是弱一致性,而是处于两者之间的单调一致性。它依靠事务ID和版本号,保证了数据的更新和读取是有序的。

ZAB协议所定义的三种节点状态:

  • Looking :选举状态。
  • Following :Follower节点(从节点)所处的状态。
  • Leading :Leader节点(主节点)所处状态。

假如Zookeeper当前的主节点挂掉了,集群会进行崩溃恢复。ZAB的崩溃恢复分成三个阶段:

  1. Leader election 选举阶段,此时集群中的节点处于Looking状态。
  2. Discovery 发现阶段,用于在从节点中发现最新的ZXID和事务日志。
  3. Synchronization 同步阶段,把Leader刚才收集得到的最新历史事务日志,同步给集群中所有的Follower。

2 如何保证保证事务的顺序一致性?

zookeeper采用了递增的事务编号(zxid)来标识事务。zxid是一个64位的数字,包含epoch和计数两部分,高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch。低32位用于递增计数。

3 Zookeeper的应用场景

  1. 分布式锁

利用Zookeeper的临时顺序节点,可以轻松实现分布式锁。

  1. 服务注册和发现

利用Znode和Watcher,可以实现分布式服务的注册和发现。最著名的应用就是阿里的分布式RPC框架Dubbo。

  1. 共享配置和状态信息

Redis的分布式解决方案Codis,就利用了Zookeeper来存放数据路由表和 codis-proxy 节点的元信息。同时 codis-config 发起的命令都会通过 ZooKeeper 同步到各个存活的 codis-proxy。

此外,Kafka、HBase、Hadoop,也都依靠Zookeeper同步节点信息,实现高可用。


Show Disqus Comments

Post Directory