ZooKeeper是一个开源的分布式协调服务(a service for coordinating processes of distributed applications),由雅虎公司建立,是Google Chubby的开源实现(Google Chubby是有名的分布式锁服务,GFS和Big Table等大型系统都用它来解决分布式协调、Master选举等一系列与分布式锁服务相关的问题)。分布式程序能够基于ZooKeeper实现负载均衡,命名服务,分布式锁等功能。ZooKeeper将全量数据都存在内存中,实现提升服务器吞吐、减小延迟的目的。node
上面的英文说的足够简而意赅了,a service for coordinating processes of distributed applications。是为了协调分布式应用的,到底解决什么样的问题呢。相信你们的Java基础都不错,我的以为仍是拿锁举例子比较好理解,在单机式中,咱们想保证多个线程争抢,最后只有一个线程争抢到执行权(锁)并执行你想要让他作的业务代码,最简单的方式,能够用:算法
synchronized (obj){
//业务逻辑
}
那么在分布式的状况下呢?怎么保证,同一个服务部署在不一样机器上实现如上目标呢?那么这就是分布式协调服务要干的事情。分布式协调远远比同一个进程里的协调复杂得多,因此相似Zookeeper这类分布式协调服务就应运而生。在解决分布式数据一致性上,除了ZooKeeper,目前没有一个成熟稳定且被大规模应用的开源方案。且愈来愈多的大型分布式项目如HBase、Storm都已经使用ZooKeeper做为其核心组件,用于分布式协调。数据库
ZooKeeper能够保证以下分布式一致性特性:安全
在立项初期,考虑到以前内部不少项目都是使用动物的名字来命名的(例如著名的Pig项目),雅虎的工程师但愿给这个项目也取一个动物的名字。时任研究院的首席科学家 Raghu Ramakrishnan 开玩笑地说:“在这样下去,咱们这儿就变成动物园了!”此话一出,你们纷纷表示就叫动物园管理员吧,由于各个以动物命名的分布式组件放在一块儿,雅虎的整个分布式系统看上去就像一个大型的动物园了。而 Zookeeper 正好要用来进行分布式环境的协调,因而,Zookeeper 的名字也就由此诞生了。服务器
在ZooKeeper中,集群有3个角色:Leader、Follower和Observer三种角色。数据结构
Leader:ZooKeeper集群中全部机器经过选举过程选定集群中的一台机器为Leader,事务请求惟一调度者和处理者,保证集群事务处理的顺序性app
Follower:为客户端提供读服务、参与Leader选举过程、参与写操做的“过半写成功”策略,收到写事务请求直接转发给Leader负载均衡
Observer:为客户端提供读服务,在不影响集群事务处理能力的前提下提高集群的非事务处理能力框架
Session是ZooKeeper中的会话实体,表明了一个客户端会话,一个客户端链接指客户端和服务器之间的一个TCP长链接。经过这个链接,客户端可以作如下事情分布式
- 向ZooKeeper服务器发送请求并接收响应
- 心跳检测
- 接收来自服务器的Watch事件
数据节点(Znode)是指数据模型中的数据单元,ZooKeeper内存数据存储的核心是DataTree,是一个树的数据结构,表明了内存中的一份完整的数据,由斜杠"/"进行分割的路径,就是一个Znode,每一个Znode都保存本身的数据内容
每一个Znode都有三种类型的版本信息,对节点数据变更会引发版本号变化
version:当前数据节点数据内容的版本号
cversion:当前数据节点子节点的版本号
aversion:当前数据节点ACL变动版本号
事件监听器(Watcher)是ZooKeeper很是重要的特性,咱们能够在节点上注册Watcher,而且在一些特性事件触发时候,服务器将事件通知到客户端上
ZooKeeper使用ACL(Access Control Lists)权限控制机制保证数据安全,有5个权限:
CREATE:建立子节点的权限
READ:获取节点数据和子节点列表的权限
WRITE:更新节点数据的权限
DELETE:删除子节点的权限
ADMIN:设置节点ACL的权限
咱们能够回头看最上面的图,Hbase,Hadoop,Kafka等已经被普遍应用在愈来愈多的大型分布式系统中,用来解决诸如配置管理,分布式通知/协调、集群管理和Master选举等一系列分布式问题
ZooKeeper在阿里的实践有Dubbo,消息中间件Metamorphosis,分布式数据库同步系统Otter,实时计算引擎Jstorm等
能够这么说,No ZAB,No ZooKeeper。ZAB协议是整个ZooKeeper框架的核心所在。
ZooKeeper是一个高可用的分布式数据管理与协调框架。基于对ZAB算法的实现,ZooKeeper成为了解决分布式环境中数据的一致性问题的利器。ZAB协议的全称是ZooKeeper Atomic Broadcast(ZooKeeper原子消息广播协议)。ZAB协议是一种特别为ZooKeeper设计的崩溃可恢复的原子消息广播算法。
全部事务请求必须由惟一的Leader服务器来协调处理,其余服务器则成为Follower服务器。Leader服务器负责将事务请求转换成一个提议,并将该提议分发到集群中的全部Follower服务器,以后Leader服务器须要等待全部Follower的响应,一旦超过半数的Follower服务器进行了正确的反馈后(不须要等待集群中全部的Follower服务器都反馈响应),那么Leader就会再次向全部Follower服务器分发Commit消息,要求对前一个提议进行提交。
首先先来看一下选举算法出现的一些专有术语
SID是一个数据,标识一台ZooKeeper集群中的机器,SID不能重复,和myid值同样。(集群的配置文件中,server.id=host:port:port,这里的id就是myid,咱们还须要在dataDir参数的目录建立myid文件,就是这里的id)
ZXID是一个事务ID,标记惟一一次服务器状态的变动,某一时刻,集群中的每台机器的ZXID不必定都一致,以前已经说过了。它是一个64位的数字,低32位能够看做递增计数器,高32位表明Leader周期epoch的编号
咱们能够看下Vote的数据结构:
接下来咱们来解释一下每一个字段的意思:
id:被选举的Leader的SID值
zxid:被选举的Leader的事务ID
electionEpoch:逻辑时钟
peerEpoch:被选举的Leader的epoch
state:当前服务器的状态
quorum=(n/2+1),假如集群总数是3,那么quorum就是2
阶段一就是Leader选举过程(服务器启动期间或者服务器运行期间),服务器的状态进入LOCKING状态。进入选举Leader流程。
不要死记硬背具体规则,总结简单来讲,哪台服务器上的数据较新,也就是它的ZXID越大,那么越有可能成为Leader。若是几个服务器具备相同的ZXID,那么SID较大的服务器成为Leader。
规则1:若是收到投票的ZXID大于自身的ZXID,就承认收到的投票再次投出去
规则2:若是收到投票的ZXID小于自身的ZXID,则坚持本身的投票不作任何变动
规则3:若是收到投票的ZXID等于自身的ZXID,则对比二者SID,若是收到投票的SID大于自身的SID则承认收到的投票再次投出去
规则4:若是收到投票的ZXID等于自身的ZXID,而且收到投票的SID小于自身SID则坚持本身的投票不作任何变动
接下来举个例子来讲明选举的过程:
过程A:咱们假设ZooKeeper由5台机器组成,SID分别为1,2,3,4,5。ZXID分别为9,9,9,8,8。此时SID为2的机器是Leader服务器,某一时刻SID为1和2的机器出现故障,所以集群开始进行Leader选举,state切换到LOCKING状态。
过程B:第一次投票,每台机器都选本身做为被选举的对象来进行投票,因此SID为3,4,5的投票状况为(这里Vote作简化,只有SID和ZXID):(3,9),(4,8),(5,8)。
过程C:Server3收到(4,8)和(5,8)。根据规则2,不作任何投票的变动。
Server4收到(3,9)和(5,8)。根据规则1,须要变动投票为(3,9)。
Server5一样的变动投票为(3,9)。
过程D:第二轮投票后,Server3收到超过一半的票数,成为Leader
选举完成后,Leader服务器会为每个Follower服务器都准备一个队列,并将那些没有被各Follower服务器同步的事务以Proposal消息的形式逐个发送给Follower服务器,而后在提议消息以后紧接发送一个Commit消息,表示该事务被提交,等到Follower服务器都将未同步的事务从Leader服务器同步过来并成功应用到本地数据库后,Leader服务器会将该Follower服务器加入真正可用的Follower列表中
Leader服务器会给每一个Follower分配一个FIFO的队列来分送事务,Follower服务器收到事务Proposal以后以事务日志的形式写入本地磁盘,写入成功会给Leader服务器回复一个ACK。
当Leader服务器收到过半的ACK响应则广播发送Commit消息给全部Follower,而后全部服务器完成对事务的提交。