Zookeeper是分布式一致性问题的工业解决方案,是Apache Hadoop下解决分布式一致性的一个组件,后被分离出来成为Apache的顶级项目。java
工程来源:是雅虎公司内部项目,听说雅虎内部不少项目都是以动物命名,这个动物管理员的名字起的非常形象。node
被开源出来后获得开源社区的快速推动,服务端Java语言实现,棒,git有3000+的star:linux
https://github.com/apache/zookeeperandroid
集群的角色,比较典型的是Master/Slave(主备模式),zk中的概念跟这个不同,包含Leader、Follower、Observer三个角色,leader提供读和写的能力,follower只对外提供读的能力。git
客户端跟服务端交互,是先与服务端创建一个TCP长链接,会话开始,经过心跳检测与服务端保持会话有效,向服务端发送请求和接收响应。github
zk将全部的数据都加载在内存一份,同时有事务日志文件(持久化文件),服务端会定时dump快照数据,重启机器的时候会根据快照和事务日志恢复内存数据库的数据,这跟redis的AOF和RDB概念相似。redis
zk上的数据的结构跟linux文件系统很像,是个树状结构算法
节点类型包括:数据库
其中临时节点特性就是建立它的主体消失后,它就跟着消失了。后续的应用就是利用的节点的特性实现的。apache
这个应该是zookeeper最重要的概念之一了,zk容许用户在特定的节点(znode)上注册watcher,而且在特定事件触发的时候,zk服务端会将事件通知到感兴趣的客户端上。
伪集群的搭建:
启动成功后,命令行链接zk,能够用指令作些增删改查的操做
telnet 127.0.0.1 2181
stat:能够看集群的状态信息
每次事务操做,会在dataDir的目录下的事务日志,是序列化的二进制文件,zookeeper提供了查看事务日志的工具类LogFormatter
利用zookeeper的特性,能够比较方便的构建分布式应用会涉及的核心功能,好比:配置中心、命名服务、分布式协调/通知、集群的管理、master选举、分布式锁等
如下应用基本基于zookeeper的两大特性实现
配置中心
zookeeper利用推拉结合的方式,客户端向服务端注册本身须要关注的节点,一旦该数据发生变动,那么服务器就会向相应的客户端发送watcher时间通知。
客户收到这个消息通知以后,再主动到服务端获取最新的数据。即回调的event中包含具体的数据。
这个应用的的业务员特色:
利用zookeeper的顺序节点,树形结构的数据特色,实现命名服务:
这样RPC的客户端只须要传对应的服务名字,和接口,就能找到对应的服务。
使用zookeeper实现:不一样的业务下建立一个节点,具体的节点下用zk的顺序节点(sequent)生成id当作这个业务的全局惟一id使用
ZooKeeper中特有watcher注册与异步通知机制,可以很好的实现分布式环境下不一样系统之间的通知与协调,实现对数据变动的实时处理。
使用方法一般是不一样系统都对ZK上同一个znode进行注册,监听znode的变化(包括znode自己内容及子节点的),其中一个系统update了znode,那么另外一个系统可以收到通知,并做出相应处理。
应用:
心跳检测机制:传统的方式是ping,复杂的话是创建长链接检测系统和被检测系统之间并不直接关联起来,而是经过zookeeper上某个节点关联,大大减小系统耦合
系统调度模式:某系统由控制台和推送系统两部分组成,控制台的职责是控制推送系统进行相应的推送工做。
管理人员在控制台做的一些操做,其实是修改了ZK上某些节点的状态,而ZK就把这些变化通知给他们注册Watcher的客户端,即推送系统。因而,做出相应的推送任务
做汇报模式:一些相似于任务分发系统,子任务启动后,到ZK来注册一个临时节点,而且定时将本身的进度进行汇报(将进度写回这个临时节点)
总之,使用zookeeper来进行分布式通知和协调可以大大下降系统之间的耦合。
这个应用主要得益于ZooKeeper为咱们保证了数据的强一致性
即用户只要彻底相信每时每刻,zk集群中任意节点(一个zk server)上的相同znode的数据是必定是相同的。
一个节点要么建立成功,要么失败,而且只由一个客户端建立。
独占锁:
保持独占,就是全部试图来获取这个锁的客户端,最终只有一个能够成功得到这把锁。
一般的作法是把ZK上的一个znode看做是一把锁,经过create znode的方式来实现。全部客户端都去建立/distribute_lock节点,最终成功建立的那个客户端也即拥有了这把锁。
共享时序控制锁:
Zookeeper很容易实现这个功能,实现方式是须要得到锁的Server,建立一个EPHEMERAL_SEQUENTIAL目录节点。
而后调用getChildren方法获取当前的目录节点列表中最小的目录节点是否是就是本身建立的目录节点。
若是正是本身建立的,那么它就得到了这个锁,若是不是,那么它就调用exists(String path, boolean watch)方法,并监控Zookeeper上目录节点列表的变化,一直到本身建立的节点是列表中最小编号的目录节点,从而得到锁。
释放锁很简单,只要删除前面它本身所建立的目录节点就好了。
master选举应用图
有个容易理解的方案,依靠关系型数据库主键的特性,集群的机器同时往一张表里插入数据,数据库会自动进行主键冲突检查,能够选择插入成功的客户端做为master
这种方式存在一个问题就是,master机器挂了,没有人通知
zk实现能够方便作到这一点:zk的建立节点api接口,具备强一致性,可以保证客户端并发建立的时候,最终必定只有一个客户端建立成功。
应用举例:集群机器存活性监控系统,例如:
监控系统在/clusterServers节点注册一个watcher监听,那么但凡进行动态添加机器的操做,就在/clusterServers下建立一个临时节点, /clusterServers/ip。
这样监控系统就可以实时的检测到机器的变更,经过getChild方法获取全部的临时节点,来判断增长的机器。
当有机器down调或者手动下线,相应临时节点会消失,监控系统也会接收到,来处理监控服务的具体业务
具体服务器部署agent实现
zookeeper的HA设计实现
以上说了那么多犀利实用的应用场景,它们依赖zookeeper,说明这些应用服务的高可用性依赖的zookeeper自己的HA。
zk的选举算法
算法协议zab协议,“少数服从多数”协议一种
3.4.0版本以后Zookeeper只保留了TCP版本的FastLeaderElection选举算法
分析选举算法前,先熟悉了解下zk的一些术语定义解释:
集群数量是4,quorum=2,集群数量是5,quorum=3
当哪些状况发生时会出发leader从新选举呢?
当zk的一台服务器出现如下两种状况的时候,会进入leader选举流程
对于第一种状况,即已经存在一台leader服务器,当改机器试图去选举leader的时候,会被告知当前服务器的leader信息,对于该机器仅仅须要和leader创建链接,并进行状态同步便可
主要看下第二种状况:
有两种状况致使集群不存在leader,一个是集群刚启动初始化的时候,另外一种状况是运行期间leader所在服务器挂了。
不管哪一种状况集群全部集群都处在一个找leader的状态,称做Looking状态,开始想其余机器发送消息投票
开始leader选举投票的协议规则是怎样呢?
5台机器宕机两台后,leader选举的过程图示
所以,一个错误的认识,为了使zookeeper集群能顺利的选出leader,必须将zookeeper集群的服务器数部署为奇数。
从上边例子能看出来部署任意台机器都可以正常选举运行。部署奇数台是官方给的建议,由于奇数和奇数+1的容灾能力是同样的。好比:
5台服务器,可以对2台机器挂掉的状况进程容灾
6台服务器,可以对2台机器挂掉的状况进程容灾,若是挂掉3台,剩下的机器就没法实现过半了。