ZooKeeper(1)--ZooKeeper概述

参考于ZooKeeper学习第一期---Zookeeper简单介绍

Zookeeper是什么?

ZooKeeper是一种为分布式应用所设计的高可用高性能一致的开源协调服务,它提供了一项基本服务:分布式锁服务

协调服务--""

Zookeeper主要应用于分布式系统,协调分布式系统下不同机器的多个线程对临界资源调用.

如果是在同一台机器,不同线程之间的协调是比较容易的.可以对临界资源加锁.当一个线程要使用这个临界资源的时候,要先获取,并一直独自享有这个资源,其他进程是无法使用这个临界资源.直到这个线程调用完这个资源或发生了异常,就会将锁释放,这时其他线程才可以再去获取这个锁,来调用这个资源.

但是这个锁在分布式系统中就没有这么"好用".

分布式系统所面临的问题

在分布式系统中,不同的系统之间的联系是通过网络来进行的,这就涉及到一个问题:网络稳定性问题.

在同一台机器中,一个线程调用服务只有两种情况:调用成功和调用失败,抛出异常.但是在分布式系统,由于网络的不稳定,会出现一种情况,在一个线程获取到锁并在调用完之后,发送信息给服务器,告诉服务器已经完成任务,可以释放锁,但是由于网络原因,这个信息丢失了,而其他线程一直等待着锁的释放,导致了死锁.

还有一种情况,需要A,B两个线程按顺序调用服务C,在时间上 A先调用,B后调用,但是由于网络原因,可能会导致BA先到,导致了难以预料的错误.

其次,在分布式环境中为了提升可靠性,我们往往会部署多套服务,但是如何在多套服务中达到一致性,这在同一台机器上多个进程之间的同步相对来说比较容易办到,但在分布式环境中确实一个大难题.

Zookeeper使用了分布式锁来解决这些问题.

Zookeeper概述

那么Zookeeper是如何实现分布式锁的呢?除此之外,Zookeeper还通过什么方式实现了配置维护、组服务、分布式消息队列分布式通知/协调服务.

Zookeeper设计了一种数据结构—Znode,然后在该数据结构的基础上定义了一些原语,也就是一些关于该数据结构的一些操作。有了这些数据结构和原语还不够,因为我们的ZooKeeper是工作在一个分布式的环境下,我们的服务是通过消息以网络的形式发送给我们的分布式应用程序,所以还需要一个通知机制——Watcher机制。所以ZooKeeper所提供的服务主要是通过:数据结构+原语+watcher机制,三个部分来实现的.

Zookeeper的数据模型Znode

Zookeeper的结构和文件系统非常相似,都是一种树形结构.

ZooKeeper树中的每个节点被称为—Znode。和文件系统的目录树一样,ZooKeeper树中的每个节点可以拥有子节点。但也有不同之处:

引用方式

Znode通过路径访问,而且必须是绝对路径,开头必须为"/",而不能是相对路径,比如说想访问Storage节点,则必须是/Baidu/Yun/Storage.字符串"/zookeeper"用以保存管理信息,比如关键配额信息。

Znode结构

Znode兼具文件与目录的属性,即可以当做一个文件:存储一些数据,原信息,ACL,时间戳等信息,也可以当做一个目录:作为路径标识的一部分,并拥有子节点.

Znode由三部分组成:

stat:状态信息,描述Znode的版本,权限的信息

data:存储一些数据.

children:存储该节点的子节点.

Znode虽然又可以存储数据的部分,但其一般不用于存储一些普通的数据,其通常被用于存储一些对分布式系统比较重要的调度信息,如分布式应用中的配置文件信息状态信息汇集位置等等,而且Znode的数据大小被限制在1M以内,但常规使用中,我们存储的数据应该远远小于此数值.

数据访问

读操作将获取与节点相关的所有数据,写操作也将替换掉节点的所有数据。另外,每一个节点都拥有自己的ACL(访问控制列表),这个列表规定了用户的权限,即限定了特定用户对目标节点可以执行的操作。

节点类型

Zookeeper中的节点有两种,分别为临时节点ephemeral永久节点persistent.节点的类型在创建的时候就会被确定,而且不能修改.

临时节点:该节点的生命周期依赖于会话,一旦会话(session)结束,临时节点将自动删除,此外,临时节点不允许有子节点.

永久节点:该节点永远存在,不依赖域会话,只能被手动删除,允许有子节点,且子节点可以是临时节点,也可以是永久节点.

顺序节点:当创建Znode的时候,用户可以请求在ZooKeeper的路径结尾添加一个递增的计数。这个计数对于此节点的父节点来说唯一的,它的格式为"%10d"(10位数字,没有数值的数位用0补充,例如"0000000001")。当计数值大于232-1时,计数器将溢出。

观察

客户端可以在节点上设置监视器,watch,其作用是在节点发生变化(增删改查)的时候,会向客户端发送相对应的通知,注意的是,这个通知会且只会发送一次.

Zookeeper的版本信息

Zookeeper主要通过zxid属性来维护版本信息,致使ZooKeeper节点状态改变的每一个操作都将使节点接收到一个Zxid格式的时间戳,并且这个时间戳全局有序。也就是说,每个对节点的改变都将产生一个唯一的Zxid。如果Zxid1的值小于Zxid2的值,那么Zxid1所对应的事件发生在Zxid2所对应的事件之前。

实际上,ZooKeeper的每个节点维护者三个Zxid值,为别为:cZxidmZxidpZxid

 cZxid 是节点的创建时间所对应的Zxid格式时间戳。
② mZxid:是节点的修改时间所对应的Zxid格式时间戳。

实现中Zxid是一个64为的数字,它32epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个 新的epoch32是个递增计数 (2) 版本号

对节点的每一个操作都将致使这个节点的版本号增加。每个节点维护着三个版本号,他们分别为:

① version:节点数据版本号
② cversion:子节点版本号
③ aversion:节点所拥有的ACL版本号

 

Zookeeper的节点属性

czxid

节点被创建的zxid

mzxid

节点被修改的zxid

ctime

节点被创建的时间

mtime

节点被修改的时间

version

节点被修改的版本号

cversion

节点所拥有的子节点被修改的版本号

aversion

节点的ACL(权限管理)被修改的版本号

ephemeralowner

如果该节点为临时节点,则为该节点拥有者的会话ID,否则为0

dataLength

节点数长度

numChildren

节点用的子节点长度

pzxid

该节点的子节点(或该节点)的最近一次 创建 / 删除 的时间戳对应,只与 本节点 / 该节点的子节点,有关;与孙子节点无关。

 

Watch触发器

ZooKeeper可以为所有的读操作设置watch,这些读操作包括:exists()getChildren()getData()watch事件是一次性的触发器,每次都需要重新注册,并且客户端在会话异常结束时不会收到任何通知,watch的对象状态发生改变时,将会触发此对象上watch所对应的事件。watch事件将被异步地发送给客户端.

watch来说,有三个主要特性:

  •   

一次性触发:观察事件会在观察的数据改变时被主动发送给客户端。举个例子,如果一个客户端调用了getData("/znode1", true),也就是在/znode1上设置了一个观察者,在这之后,如果/znode1发生了改变或者被删除了,这个客户端会受到观察事件的提醒,但是,如果之后/znode1又发生了改变或者删除,这个客户端是不会收到事件提醒的了。

  •  

有序地发送给客户端watch事件异步发送至观察者。比如说client执行一次写操作,节点数据内容发生变化,操作返回后,而watch事件可能还在发往client的路上这种情况下,但ZooKeeper保证了一个顺序:一个客户端在收到watch事件之前,一定不会看到它设置过watch节点的变动。网络时延和其他因素可能会导致不同的客户端看到watch和更新返回值的时间不同。但关键点是,从客户端接收到的watch事件顺序一定和ZooKeeper服务所看到的事件顺序是一致的。

  •  

观察者观察的数据ZooKeeper中一个节点发生改变会有不同的方式。也就是,在zk服务端中,维护着两个观察者列表:数据观察者、子节点观察者。getData()exists()设置的是数据观察者,getChildren()设置的是子节点观察者。

① exists操作上的watch,在被监视的Znode创建删除数据更新时被触发。
 getData操作上的watch,在被监视的Znode删除数据更新时被触发。在被创建时不能被触发,因为只有Znode一定存在,getData操作才会成功。
 getChildren操作上的watch,在被监视的Znode的子节点创建删除,或是这个Znode自身删除时被触发。可以通过查看watch事件类型来区分是Znode,还是他的子节点被删除:NodeDelete表示Znode被删除,NodeDeletedChanged表示子节点被删除。

Zookeeper中的角色

» 领导者(leader),负责进行投票的发起和决议,更新系统状态
  » 学习者(learner),包括跟随者(follower)和观察者(observer),follower用于接受客户端请求并想客户端返回结果,在选主过程中参与投票
  » Observer可以接受客户端连接,将写请求转发给leader,但observer不参加投票过程,只同步leader的状态,observer的目的是为了扩展系统,提高读取速度
  » 客户端(client),请求发起方

Zookeep节点数据操作流程

1.ClientFollwer发出一个写的请求

2.Follwer把请求发送给Leader

3.Leader接收到以后开始发起投票并通知Follwer进行投票

4.Follwer把投票结果发送给Leader

5.Leader将结果汇总后如果需要写入,则开始写入同时把写入操作通知给Leader,然后commit;

6.Follwer把请求结果返回给Client

 

• Follower主要有四个功能:
• 1. Leader发送请求(PING消息、REQUEST消息、ACK消息、REVALIDATE消息);
• 2 .接收Leader消息并进行处理;
• 3 .接收Client的请求,如果为写请求,发送给Leader进行投票;
• 4 .返回Client结果。
• Follower的消息循环处理如下几种来自Leader的消息:
• 1 .PING消息: 心跳消息;
• 2 .PROPOSAL消息:Leader发起的提案,要求Follower投票;
• 3 .COMMIT消息:服务器端最新一次提案的信息;
• 4 .UPTODATE消息:表明同步完成;
• 5 .REVALIDATE消息:根据LeaderREVALIDATE结果,关闭待revalidatesession还是允许其接受消息;
• 6 .SYNC消息:返回SYNC结果到客户端,这个消息最初由客户端发起,用来强制得到最新的更新

猜你喜欢

转载自blog.csdn.net/QEcode/article/details/84306105