Zookeeper
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。
ZooKeeper的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。
ZooKeeper包含一个简单的原语集,提供Java和C的接口。
ZooKeeper代码版本中,提供了分布式独享锁、选举、队列的接口,代码在$zookeeper_home\src\recipes。其中分布锁和队列有Java和C两个版本,选举只有Java版本。
概念
本将介绍 ZooKeeper 的几个核心概念。这些概念贯穿于之后对 ZooKeeper 更深入的讲解,因此有必要预先了解这些概念
集群角色
在 ZooKeeper 中,有三种角色:
领导者(leader),负责进行投票的发起和决议,更新系统状态
学习者(learner),包括跟随者(follower [ˈfɑːloʊər])和观察者(observer [əbˈzɜːrvər])。
follower用于接受客户端请求并向客户端返回结果,在选主过程中参与投票
Observer可以接受客户端连接,将写请求转发给leader,但observer不参加投票过程,只同步leader的状态,observer的目的是为了扩展系统,提高读取速度
客户端(client),请求发起方
一个 ZooKeeper 集群同一时刻只会有一个 Leader,ZooKeeper集群的所有机器通过选举过程来选定一台被称为Leader的机器,Leader服务器为客户端提供读和写服务。其他都是 Follower 或 Observer。
节点状态:
每个集群中的节点都有一个状态 LOOKING, FOLLOWING, LEADING, OBSERVING。都属于这4种,每个节点启动的时候都是LOOKING状态,如果这个节点参与选举但最后不是leader,则状态是FOLLOWING,如果不参与选举则是OBSERVING,leader的状态是LEADING。
关于ZooKeeper集群服务器数:
ZooKeeper 官方建议集群服务器的数量为奇数,这是因为一个 ZooKeeper 集群如果要对外提供可用的服务,那么集群中必须要有过半的机器正常工作并且彼此之间能够正常通信。基于这个特性,如果想搭建一个能够允许 N 台机器 down 掉的集群,那么就要部署一个由 2*N+1 台服务器构成的 ZooKeeper 集群。因此,一个由 3 台机器构成的 ZooKeeper 集群,能够在挂掉 1 台机器后依然正常工作,而对于一个由 5 台服务器构成的 ZooKeeper 集群,能够对 2 台机器挂掉的情况进行容灾
ZooKeeper可伸缩性:
那么,ZooKeeper为什么要引入Observer这个角色呢?其实在ZooKeeper中引入Observer,主要是为了使ZooKeeper具有更好的可伸缩性。那么,何为可伸缩性?如果我们的工作负载可以通过给系统分配更多的资源来分担,那么这个系统就是可伸缩的;一个不可伸缩的系统却无法通过增加资源来提升性能,甚至会在工作负载增加时,性能会急剧下降
Znode
ZooKeeper维护一个类似Linux文件系统的数据结构,用于存储数据
数据模型结构是一种树形结构,由许多节点构成,每个节点叫做ZNode(ZooKeeper Node),每个节点对应一个唯一路径,通过该路径来标识节点,如/app1/p_1,其中 app1和p_1都是 ZNode。每个 ZNode 上都会保存自己的数据内容。
Watcher
ZooKeeper是一个基于观察者(watcher)模式设计的分布式服务管理框架
- ZooKeeper负责管理和维护项目的公共数据,并授受观察者的注册(订阅) 2. 一旦这些数据发生变化,ZooKeeper就会通知已注册的观察者
- 此时观察者就可以做出相应的反应
简单来说,客户端注册监听它关心的目录节点,当目录节点发生变化时,ZooKeeper会通知客户端
ZooKeeper支持Watch操作,Client可以在某个ZNode上设置一个Watcher,来Watch该ZNode上的变化。如果该ZNode上有相应的变化,就会触发这个Watcher,把相应的事件通知给设置Watcher的Client。需要注意的是,ZooKeeper中的Watcher是一次性的,即触发一次就会被取消,如果想继续Watch的话,需要客户端重新设置Watcher,该机制是 ZooKeeper 实现分布式协调服务的重要特性。
事务操作
在ZooKeeper中,能改变ZooKeeper服务器状态的操作称为事务操作。一般包括数据节点创建与删除、数据内容更新和客户端会话创建与失效等操作。对应每一个事务请求,ZooKeeper 都会为其分配一个全局唯一的事务ID,用 ZXID 表示,每一个 ZXID 对应一次更新操作,从这些 ZXID 中可以间接地识别出 ZooKeeper 处理这些事务操作请求的全局顺序。
创建任意节点, 或者更新任意节点的数据, 或者删除任意节点, 都会导致Zookeeper状态发生改变, 从而导致zxid的值增加。由于zxid的递增性质, 如果zxid1小于zxid2, 那么zxid1肯定先于zxid2发生。
实际上,ZooKeeper的每个节点维护着三个zxid值,为别为:cZxid、mZxid、pZxid。
cZxid: 是该节点创建时所对应的事物ID。
mZxid:是该节点最近一次被修改时所对应的事物ID,与其子节点无关。
pZxid:是该节点的子节点最近一次被修改时的事物ID。
ZooKeeper的工作原理
Zab协议
Zookeeper的核心是原子广播,这个机制保证了各个server之间的同步。实现这个机制的协议叫做Zab协议。Zab协议有两种模式,它们分别是恢复模式和广播模式。
当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数server完成了和leader的状态同步以后,恢复模式就结束了。
其中,所谓的状态同步是指数据同步,用来保证集群中存在过半的机器能够和 Leader 服务器的数据状态保持一致。
一旦leader已经和过半数的follower进行了状态同步后,他就可以开始广播消息了,即进入广播状态。这时候当一个server加入zookeeper服务中,它会在恢复模式下启动,发现leader,并和leader进行状态同步。待到同步结束,它也参与消息广播。Zookeeper服务一直维持在Broadcast状态,直到leader崩溃了或者leader失去了大部分的followers支持。
应用场景
配置管理
场景:集群环境、服务器的许多配置都是相同的,如:数据库连接信息,当需要修改这些配置时必须同时修改每台服务器,很麻烦
解决:把这些配置全部放到ZooKeeper上,保存在ZooKeeper的某个目录节点中,然后所有的应用程序(客户端)对这个目录节点进行监视Watch,一旦配置信息发生变化,ZooKeeper会通知每
命名服务(Naming Service),即注册中心——服务注册与发现
命名服务也是分布式系统中比较常见的一类场景。在分布式系统中,通过使用命名服务,客户端应用能够根据指定名字来获取资源或服务的地址,提供者等信息。
个客户端,然后从ZooKeeper获取新的配置信息,并应用到系统中。
软负载均衡
ZooKeeper本身是不提供负载均衡策略的,需要自己实现,所以准确的说,是在负载均衡中使用ZooKeeper来做集群的协调(也称为软负载均衡)
心跳检测
机器间的心跳检测机制是指在分布式环境中,不同机器(或进程)之间需要检测到彼此是否在正常运行,例如A机器需要知道B机器是否正常运行。在传统的开发中,我们通常是通过主机直接是否可以相互PING通来判断,更复杂一点的话,则会通过在机器之间建立长连接,通过TCP连接固有的心跳检测机制来实现上层机器的心跳检测,这些都是非常常见的心跳检测方法。
下面来看看如何使用ZooKeeper来实现分布式机器(进程)间的心跳检测。
基于ZooKeeper的临时节点的特性,可以让不同的进程都在ZooKeeper的一个指定节点下创建临时子节点,不同的进程直接可以根据这个临时子节点来判断对应的进程是否存活。通过这种方式,检测和被检测系统直接并不需要直接相关联,而是通过ZooKeeper上的某个节点进行关联,大大减少了系统耦合