zookeeper -- softwbc 发布于:2017年12月27日 浏览量:1279  |

1        zookeeper

1.1      简述

配置管理(比如:数据库连接)、

名字服务(类似DNS解析域名,针对服务的)、

分布式锁(保证某时刻只让一个服务干活,服务问题释放锁,迅速fail over到另外服务:leader选举)、

集群管理(新节点加入,故障节点退出集群,其他节点感知变化。当使用方访问服务时,发现该服务,服务发现:Dubbo

 

Apache ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,由ClientServer构成,Server提供了一致性复制和存储服务,Client包含一个简单的原语集,分布式应用程序可以基于它实现同步服务,配置维护和命名服务等。ZooKeeper的设计非常易于编程,ZooKeeper维护着一个hierarchal(层次)的名字空间,它采用树形的数据结构,类似于标准文件系统。因为想要从零实现一个分布式协作服务是非常难的。最常见的问题就是竞争条件和死锁。Apache ZooKeeper的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。

 

Zookeepr的数据都存放在内存中(更新数据也会持久化到磁盘),所以它的吞吐量会非常高,同时延迟会很低。ZooKeeper的实现更重视high performance(高性能), highly available(高可用性), strictly ordered access(严格有序访问)。Zookeeper性能方面的表现让它能够用于大型分布式系统,高可用性可以避免出现单点故障,严格有序访问可以让Client实现复杂的同步原语。

 

1.2      系统模型


上图的Server组成了Zookeeper服务,每个Server都知道彼此的存在。这些server在内存中保持着状态的镜像,还通过transaction logs和快照持久到硬盘中。只要集群中多数Server可访问,那么ZooKeeper服务就可用。

Clients会连接到某一个ZooKeeper Server上。ClientServer保持一个TCP长连接,通过该TCP长连接,Client可以发送请求,得到response,得到watch event,还有发送心跳(客户端和服务端通过心跳来保持连接,即session)。如果和ServerTCP长连接断了,那么Client就会连接到另外一个Server上。

 

Zookeeper是有序的:Zookeeperstamps(数字)作为所有事务的顺序。

Zookeeper是非常快的:特别是以读为主的情况下,Zookeeper应用程序可以运行在数千台机器上,它性能表现最佳的是在读写比率为10:1的情况下。

1.1      数据模型


ZooKeeper数据模型的结构与Unix文件系统很类似,整体上可以看作是一棵树,每个节点称做一个ZNode。每个ZNode上可存储少量数据(默认是1M, 可以通过配置修改通常不建议在ZNode上存储大量的数据),下面说说Zookeeper几个比较重要的概念:

1.1.1       Znode

1Zookeeper节点称为Znode,每个节点都有唯一的路径标示。Znode分类两类:1,普通的Znode2ephemeral(临时)Znode
2Znode维护了stat结构,里面包含数据,ACL变更的版本号,还有时间戳去允许缓存验证和协调更新。当znodedata改变了,版本号就会增加
3Znode可以有子节点,并且Znode可以存放数据,但是ephemeral(临时)Znode不能有子节点。
4Znode数据可以有多个版本,客户端可以根据版本获取该节点的数据。
5,如果创建ephemeral(临时)Znode的客户端和服务端失去连接的话,那么该零时节点也自动删除。
6Znode可以自动编号。
7Znode中可以添加watch,该watch用于监控该节点存储的数据是否有修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端。
8Znode的读写操作都具备原子性,每个Znode都有一个访问控制列表(ACL)来控制谁能做什么操作。

 

1.1.2       Session

Client与ZooKeeper之间的通信,需要创建一个Session,这个Session会有一个超时时间。因为ZooKeeper集群会把Client的Session信息持久化,所以在Session没超时之前,Client与ZooKeeper Server的连接可以在各个ZooKeeper Server之间透明地移动。
在实际的应用中,如果Client与Server之间的通信足够频繁,Session的维护就不需要其它额外的消息了。否则,ZooKeeper Client会每T/3 ms发一次心跳给Server,如果Client 2T/3 ms没收到来自Server的心跳回应,就会换到一个新的ZooKeeper Server上。这里T是用户配置的Session的超时时间。

1.1.3       Watcher

ZooKeeper支持一种Watch操作,Client可以在某个ZNode上设置一个Watcher,来WatchZNode上的变化。如果该ZNode上有相应的变化,就会触发这个Watcher,把相应的事件通知给设置WatcherClient。需要注意的是,ZooKeeper中的Watcher是一次性的,即触发一次就会被取消,如果想继续Watch的话,需要客户端重新设置Watcher

1.1.4       事务日志和快照

dataDir目录指定了Zookeeper的数据目录,用于存储Zookeeper的快照文件(snapshot)。

dataLogDir定义了Zookeeper的事务日志目录,目录存放Zookeeper的事务日志,正常情况下,所有的更新操作在返回客户端更新成功前,Zookeeper肯定已经将本次更新操作写入到事务日志了(即磁盘中)。事务日志的文件名是log.zxid是写入这个文件的第一个事务id。在完成若干次事务后会一次数据快照,将当前Server上所有节点的状态以快照文件的形式dump到磁盘上去,即snapshot文件。

 

1.2      角色

Zookeepr角色分可以分为四类:

角色

描述

Leader

领导者负责进行投票的发起和决议,更新系统状态

Follower

1,Follower负责接收Client请求,并向客户端返回结果

2,在选Leader的过程中参与投票

Observer

ObServer可以接收客户端的连接,将写请求转发到Leader节点,但是ObServer不参与投票和选举,仅仅接收投票和选举的结果。它的作用主要是用来扩展系统,提高读取的速度。ObServer是zookeeper-3.3.0新加的角色。

Client

请求发起方

1.3      特性

顺序一致性:按照客户端发送请求的顺序更新数据。Zookeeper是不属于强一致性,因为watcher没办法扑捉到每次的变化。
原子性:更新要么成功,要么失败,不会出现部分更新。
单一系统映像 :无论客户端连接哪个server,都会看到同一个视图。
可靠性:具有简单、健壮、良好的性能,如果消息被到一台服务器接受,那么它将被所有的服务器接受。
时效性:Zookeeper保证客户端将在一个时间间隔范围内获得服务器的更新数据,或者服务器失效的信息。但由于网络延时等原因,Zookeeper不能保证两个客户端能同时得到刚更新的数据,如果需要最新数据,应该在读数据之前调用sync()接口。

1.4      原理和Leader选举

Zookeeper核心是原子广播,通过Zab协议保证各个Server之间数据的同步。Zab协议有两种模式,分别是恢复模式(选举Leader)和广播模式(同步)。服务启动或者Leader崩溃后,Zab就会进入了恢复模式,当Leader被选举出来,且大多数Server完成了和leader的状态同步以后,恢复模式就结束了。状态同步保证了Leader和Server具有相同的系统状态。

为了保证事务的顺序一致性,Zookeeper采用了递增的事务id号(zxid)来标识事务。所有的提议(proposal)都在被提出的时候加上了zxid。实现中zxid是一个64位的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的统治时期。低32位用于递增计数。

每个Server在工作过程中有四种状态:
    LOOKING:当前Server不知道leader是谁,正在搜寻。
    LEADING:当前Server即为选举出来的leader。
    FOLLOWING:leader已经选举出来,当前Server与之同步。
    OBSERVING:不选举,只从Leader同步状态。

 

Fast选主流程:(Pasox基于消息传递的一致性算法(n/2 + 1))

Serverid:在配置server时,给定的服务器的标示id。

Zxid:服务器在运行时产生的数据id,zxid越大,表示数据越新。

Epoch:选举的轮数,即逻辑时钟。随着选举的轮数++

Server状态:LOOKING,FOLLOWING,OBSERVING,LEADING

 


一、Server刚启动(宕机恢复或者刚启动)准备加入集群,此时读取自身的zxid等信息

二、所有Server加入集群时都会推荐自己为leader,然后将(leader id 、 zxid 、 epoch)作为广播信息,广播到集群中所有的服务器(Server)。然后等待集群中的服务器返回信息。

三、收到集群中其他服务器返回的信息,此时要分为两类:该服务器处于looking状态,或者其他状态。

(1)服务器处于looking状态

首先判断逻辑时钟 Epoch:

a)如果接收到Epoch大于自己目前的逻辑时钟(说明自己所保存的逻辑时钟落伍了)。更新本机逻辑时钟Epoch,同时 Clear其他服务发送来的选举数据(这些数据已经OUT了)。然后判断是否需要更新当前自己的选举情况(一开始选择的leader id 是自己)

    判断规则rules judging:保存的zxid最大值和leader Serverid来进行判断的。先看数据zxid,数据zxid大者胜出;其次再判断leaderServerid, leader Serverid大者胜出;然后再将自身最新的选举结果(也就是上面提到的三种数据(leader Serverid,Zxid,Epoch)广播给其他server)

b)如果接收到的Epoch小于目前的逻辑时钟。说明对方处于一个比较OUT的选举轮数,这时只需要将自己的 (leader Serverid,Zxid,Epoch)发送给他即可。

c)如果接收到的Epoch等于目前的逻辑时钟。再根据a)中的判断规则,将自身的最新选举结果广播给其他 server。

 

同时Server还要处理2种情况:

a)如果Server接收到了其他所有服务器的选举信息,那么则根据这些选举信息确定自己的状态(Following,Leading),结束Looking,退出选举。

b)即使没有收到所有服务器的选举信息,也可以判断一下根据以上过程之后最新的选举leader是不是得到了超过半数以上服务器的支持,如果是则尝试接受最新数据,倘若没有最新的数据到来,说明大家都已经默认了这个结果,同样也设置角色退出选举过程。

 

(2)服务器处于其他状态(Following, Leading)

a)如果逻辑时钟Epoch相同,将该数据保存到recvset,如果所接收服务器宣称自己是leader,那么将判断是不是有半数以上的服务器选举它,如果是则设置选举状态退出选举过程

b)否则这是一条与当前逻辑时钟不符合的消息,那么说明在另一个选举过程中已经有了选举结果,于是将该选举结果加入到outofelection集合中,再根据outofelection来判断是否可以结束选举,如果可以也是保存逻辑时钟,设置选举状态,退出选举过程。

 

1.1      请求处理流程


值得注意的是, Follower/Leader上的读操作时并行的,读写操作是串行的,当CommitRequestProcessor处理一个写请求时,会阻塞之后所有的读写请求。

1.1      API

Zookeeper的一个设计目标是提供简单的编程接口,仅仅支持如下操作:

create:创建一个Znode。path是其路径,data是要存储在该Znode上的数据,createMode包括:PERSISTEN,PERSISTENT_SEQUENTAIL,EPHEMERAL,EPHEMERAL_SEQUENTAIL。

delete:删除一个Znode。可以删除指定版本的Znode,如果version设置为-1的话,就删除所有的版本。

exists:判断Znode是否存在,设置是否Watch这个Znode。

get data:读取指定Znode上的数据,并设置是否watch这个Znode。

set data:更新指定Znode的数据,并设置是否Watch这个Znode。

get children:更新指定ZNode的数据,并设置是否Watch这个Znode。

sync:把sync之前的更新操作都同步过来。

set acl:设置指定ZNode的Acl信息

get acl:获取指定ZNode的Acl信息

名称

同步

异步

watch

权限认证

create


delete


exist


getData

setData


getACL



setACL


getChildren

sync




multi



createSession




closeSession




 

1.2      其他

读、写(更新)模式:
Zookeeper集群中,客户端可以从任意一个ZooKeeper服务器读取,这一特点保证了ZooKeeper有比较好的读性能;

写的请求会先Forwarder到Leader,然后由Leader来通过ZooKeeper中的原子广播协议,将请求广播给所有的Follower,Leader收到一半以上的写成功的Ack后,就认为该写成功了,就会将该写进行持久化,并告诉客户端写成功了。

WAL(Write-Ahead-Log)和Snapshot:
ZooKeeper也有WAL,每一个更新操作,ZooKeeper都会先写WAL,然后再对内存中的数据做更新,最后向Client通知更新结果。

ZooKeeper还会定期将内存中的目录树进行Snapshot,落地到磁盘上。其实跟HDFS中的fsimage和edits log是类似的。这么做的主要目的,一当然是数据的持久化,二是加快重启之后的恢复速度,如果全部通过Replay WAL的形式恢复的话,会比较慢。

FIFO
对于每一个ZooKeeper客户端而言,所有的操作都是遵循FIFO顺序的,这一特性是由下面两个基本特性来保证的:

一是ZooKeeper Client与Server之间的网络通信是基于TCP,TCP保证了Client/Server之间传输包的顺序;

二是ZooKeeper Server执行客户端请求也是严格按照FIFO顺序的。

线性化:
ZooKeeper包括全局有序和偏序两种:

全局有序是针对服务器端。例如:在一台服务器上消息A在消息B前发布,那么所有服务器上的消息A都将在消息B前被发布;

偏序是针对客户端。例如:在同一个客户端发送消息B在消息A后发布,那么执行的顺序必将是先执行消息A然后在是消息B;

所有的更新操作都有严格的偏序关系,更新操作都是串行执行的,这一点是保证ZooKeeper功能正确性的关键。

http://zookeeper.apache.org/doc/trunk/zookeeperOver.html


关于我们 |  广告服务 |  联系我们 |  网站声明

Copyright © 2015 - 2016 DISPACE.NET |  使用帮助 |  关于我们 |  投诉建议

京ICP备13033209号-2