Zookeeper是一个开源的分布式协调服务,目前由Apache进行维护。Zookeeper能够用于实现分布式系统中常见的发布/订阅、负载均衡、命令服务、分布式协调/通知、集群管理、Master选举、分布式锁和分布式队列等功能。它具备如下特性:node
Zookeeper致力于为那些高吞吐的大型分布式系统提供一个高性能、高可用、且具备严格顺序访问控制能力的分布式协调服务。它具备如下四个目标:git
Zookeeper经过树形结构来存储数据,它由一系列被称为ZNode的数据节点组成,相似于常见的文件系统。不过和常见的文件系统不一样,Zookeeper将数据全量存储在内存中,以此来实现高吞吐,减小访问延迟。github
能够由一组Zookeeper服务构成Zookeeper集群,集群中每台机器都会单独在内存中维护自身的状态,而且每台机器之间都保持着通信,只要集群中有半数机器可以正常工做,那么整个集群就能够正常提供服务。服务器
对于来自客户端的每一个更新请求,Zookeeper都会分配一个全局惟一的递增ID,这个ID反映了全部事务请求的前后顺序。网络
ZooKeeper将数据存全量储在内存中以保持高性能,并经过服务集群来实现高可用,因为Zookeeper的全部更新和删除都是基于事务的,因此其在读多写少的应用场景中有着很高的性能表现。session
Zookeeper集群中的机器分为如下三种角色:数据结构
Zookeeper客户端经过TCP长链接链接到服务集群,会话(Session)从第一次链接开始就已经创建,以后经过心跳检测机制来保持有效的会话状态。经过这个链接,客户端能够发送请求并接收响应,同时也能够接收到Watch事件的通知。架构
关于会话中另一个核心的概念是sessionTimeOut(会话超时时间),当因为网络故障或者客户端主动断开等缘由,致使链接断开,此时只要在会话超时时间以内从新创建链接,则以前建立的会话依然有效。负载均衡
Zookeeper数据模型是由一系列基本数据单元Znode
(数据节点)组成的节点树,其中根节点为/
。每一个节点上都会保存本身的数据和节点信息。Zookeeper中节点能够分为两大类:框架
临时节点和持久节点均可以添加一个特殊的属性:SEQUENTIAL
,表明该节点是否具备递增属性。若是指定该属性,那么在这个节点建立时,Zookeeper会自动在其节点名称后面追加一个由父节点维护的递增数字。
每一个ZNode节点在存储数据的同时,都会维护一个叫作Stat
的数据结构,里面存储了关于该节点的所有状态信息。以下:
状态属性 | 说明 |
---|---|
czxid | 数据节点建立时的事务ID |
ctime | 数据节点建立时的时间 |
mzxid | 数据节点最后一次更新时的事务ID |
mtime | 数据节点最后一次更新时的时间 |
pzxid | 数据节点的子节点最后一次被修改时的事务ID |
cversion | 子节点的更改次数 |
version | 节点数据的更改次数 |
aversion | 节点的ACL的更改次数 |
ephemeralOwner | 若是节点是临时节点,则表示建立该节点的会话的SessionID;若是节点是持久节点,则该属性值为0 |
dataLength | 数据内容的长度 |
numChildren | 数据节点当前的子节点个数 |
Zookeeper中一个经常使用的功能是Watcher(事件监听器),它容许用户在指定节点上针对感兴趣的事件注册监听,当事件发生时,监听器会被触发,并将事件信息推送到客户端。该机制是Zookeeper实现分布式协调服务的重要特性。
Zookeeper采用ACL(Access Control Lists)策略来进行权限控制,相似于UNIX文件系统的权限控制。它定义了以下五种权限:
ZAB协议是Zookeeper专门设计的一种支持崩溃恢复的原子广播协议。经过该协议,Zookeepe基于主从模式的系统架构来保持集群中各个副本之间数据的一致性。具体以下:
Zookeeper使用一个单一的主进程来接收并处理客户端的全部事务请求,并采用原子广播协议将数据状态的变动以事务Proposal的形式广播到全部的副本进程上去。以下图:
具体流程以下:
全部的事务请求必须由惟一的Leader服务来处理,Leader服务将事务请求转换为事务Proposal,并将该Proposal分发给集群中全部的Follower服务。若是有半数的Follower服务进行了正确的反馈,那么Leader就会再次向全部的Follower发出Commit消息,要求将前一个Proposal进行提交。
ZAB协议包括两种基本的模式,分别是崩溃恢复和消息广播:
当整个服务框架在启动过程当中,或者当Leader服务器出现异常时,ZAB协议就会进入恢复模式,经过过半选举机制产生新的Leader,以后其余机器将重新的Leader上同步状态,当有过半机器完成状态同步后,就退出恢复模式,进入消息广播模式。
ZAB协议的消息广播过程使用的是原子广播协议。在整个消息的广播过程当中,Leader服务器会每一个事物请求生成对应的Proposal,并为其分配一个全局惟一的递增的事务ID(ZXID),以后再对其进行广播。具体过程以下:
Leader服务会为每个Follower服务器分配一个单独的队列,而后将事务Proposal依次放入队列中,并根据FIFO(先进先出)的策略进行消息发送。Follower服务在接收到Proposal后,会将其以事务日志的形式写入本地磁盘中,并在写入成功后反馈给Leader一个Ack响应。当Leader接收到超过半数Follower的Ack响应后,就会广播一个Commit消息给全部的Follower以通知其进行事务提交,以后Leader自身也会完成对事务的提交。而每个Follower则在接收到Commit消息后,完成事务的提交。
数据的发布/订阅系统,一般也用做配置中心。在分布式系统中,你可能有成千上万个服务节点,若是想要对全部服务的某项配置进行更改,因为数据节点过多,你不可逐台进行修改,而应该在设计时采用统一的配置中心。以后发布者只须要将新的配置发送到配置中心,全部服务节点便可自动下载并进行更新,从而实现配置的集中管理和动态更新。
Zookeeper经过Watcher机制能够实现数据的发布和订阅。分布式系统的全部的服务节点能够对某个ZNode注册监听,以后只须要将新的配置写入该ZNode,全部服务节点都会收到该事件。
在分布式系统中,一般须要一个全局惟一的名字,如生成全局惟一的订单号等,Zookeeper能够经过顺序节点的特性来生成全局惟一ID,从而能够对分布式系统提供命名服务。
分布式系统一个重要的模式就是主从模式(Master/Salves),Zookeeper能够用于该模式下的Matser选举。可让全部服务节点去竞争性地建立同一个ZNode,因为Zookeeper不能有路径相同的ZNode,必然只有一个服务节点可以建立成功,这样该服务节点就能够成为Master节点。
能够经过Zookeeper的临时节点和Watcher机制来实现分布式锁,这里以排它锁为例进行说明:
分布式系统的全部服务节点能够竞争性地去建立同一个临时ZNode,因为Zookeeper不能有路径相同的ZNode,必然只有一个服务节点可以建立成功,此时能够认为该节点得到了锁。其余没有得到锁的服务节点经过在该ZNode上注册监听,从而当锁释放时再去竞争得到锁。锁的释放状况有如下两种:
当锁被释放后,其余服务节点则再次去竞争性地进行建立,但每次都只有一个服务节点可以获取到锁,这就是排他锁。
Zookeeper还能解决大多数分布式系统中的问题:
更多大数据系列文章能够参见我的 GitHub 开源项目: 大数据入门指南