什么是zookeeper
简介:Apache Zookeeper是一种用于分布式应用程序的高性能协调服务,提供一种集中式信息存储服务
特点:数据存在内存中,类似文件系统的树形结构(文件和目录),高吞吐和低延迟,集群高可靠
作用:基于zookeeper可以实现分布式统一配置中心,服务注册中心,分布式锁等功能
1.zookeeper的应用案例
Hbase:使用zookeeper进行master选举,服务间协调
Solr:使用zookeeper进行集群管理,leader选举,配置管理
dubbo:服务注册
mycat:集群管理,配置管理
sharding-sphere:集群管理,配置管理
2.zookeeper的同类产品
consul
etcd
doozer
3.基本指令
ls获取子节点信息
create创建节点
delete删除节点(节点下无子节点)
rmr删除节点(节点下有子节点)相当于windows删除整个文件件
exists是否存在节点
get获取数据
set设置数据
sync等待数据进行同步
zookeeper会话session
1.一个客户端连接一个会话,由zk分配唯一会话ID
2.客户端以特定的时间间隔发送心跳以保持会话有效,tickTime
3.超过会话超时时间未收到客户端的心跳,则判定客户端死了(默认2倍tickTime,可在配置文件配置修改)
4.会话中的请求按FIFO(first in first out)顺序执行
zookeeper数据模型
层次名称空间
1.类似unix文件系统,以/为根
2.区别:节点可以包含域值关联的数据以及子节点(既是文件也是文件夹)
3.节点的路径总是表示为规范的,绝对的,斜杠分隔的路径
zonde特点
1.名称唯一,命名规范(zookeeper为保留节点名,所以不能创建节点叫zookeeper)
2.节点类型:持久,顺序(十位十进制序号例如第一个为0000000001,每个父节点一个计数器,计数超出最大范围将溢出,导致名称出现负数),临时,临时顺序
3.节点结构构成
节点数据:存储的是协调数据(状态信息,配置,位置信息等)
节点元数据(stat结构)
数据量上限:1M
stat结构的结构字段(get /节点名称 返回这些具体字段内容):
- czxid创建该节点的事务id
- mzxid最后修改该节点的事务id
- pzxid:zonde最后更新的子节点zxid
- ctime节点创建时间
- mtime节点修改时间
- dataVersion节点被修改的次数
- cversion该节点的子节点变更次数
- ephemeralOwener临时节点的所有者会话id,如果不是临时节点,则为0
- datalength该节点的数据长度
- numChildren子节点数
zookeeper中的时间
1.zxid: zookeeper中每次更新操作都对应一个唯一事务id,它是一个全局有序的戳记,如果zxid1小于zxid2,则zxid1发生在zxid2之前
2.version number版本号,对节点每次更改都会导致该节点的版本号+1
3.ticks(重要) 当使用多服务器zookeeper时,服务器使用'滴答'来定义事件的时间,如状态上传,会话超时,对等点之间的连接超时等
4.real time: zookeeper除了在znode创建和修改时将时间戳放入stat结构之外,基本不会使用realtime
zookeeper的watch监听机制
客户端可以在zonodes上设置watch,监听znode的变化
两类watch:
1.data watch监听数据变更
2.child watch监听子节点变化
触发watch事件:
created event
deleted event
changed event
child event
watch的重要特性
1.一次性触发:watch触发后即被删除,要持续监听变化,则需要持续设置watch,收到触发watch通知到设置下一次watch之间,不能可靠地得到节点发生的每个更改
2.有序性:客户端先得到watch通知,后才会看到变化结果
3.如果同时注册了多种类型watch在一个节点,那么只会收到一次watch通知
zookeeper特性
1.顺序一致性:保证客户端操作时按顺序生效的
2.原子性:更新成功或者失败,没有部分结果
3.单个系统映像:无论连接到哪个服务器,客户端都将看到相同的内容
4.可靠性:数据的变更不会丢失,除非被客户端覆盖修改
5.及时性:保证系统的客户端当时读取到的数据是最新的
zookeeper典型应用场景
1.数据发布订阅(配置中心)
znode能存数据:一个配置项一个znode或者一个配置文件一个znode
watch能监听数据改变:动态更新配置修改的最新值
2.命名服务
服务A开发完成,服务B未开发完成,服务A需要调用服务B,此时,A服务在zk监听/serviceB的节点watch事件,当B服务开发完成,在/serviceB上创建服务B的地址,就可以动态获取B的服务地址,A服务不需要重新部署或者做任何改动
3.master选举
/master节点为临时节点,选举master的过程就是创建这个节点过程,创建成功则成为master.否则注册节点watch,服务宕机,其余节点获取watch事件回调,重新争抢master;除此之外,也可以使用临时顺序节点,当前节点最小则为master,否则监听其前面一个节点的删除事件,回调时去重新判断是否最小节点(和分布式锁一个原理)
4.集群管理
/servers节点为临时顺序节点,集群中所有的节点都注册上去,当服务宕机则自动删除,从而动态感知集群中节点信息
5.分布式队列
/queue节点为持久顺序节点
生产者将任务或者消息存入这个队列节点,任务名称按照顺序添加
消费者取出所有子节点,移除最小节点,执行最小节点的任务,这样可以达到按照入队顺序来消费节点中的任务
以上实现方式是无界队列
有界队列,需要获取/queue界定当前的子节点数,如果大于则不能创建新子节点,这里判断容量需要使用分布式锁来控制,保证线程安全
6.分布式锁
/lock节点是临时顺序节点
lock方法就是创建临时顺序节点的过程,创建成功后,获取所有子节点,判断自己是否最小节点,如果是,则代表获取到了锁,否则注册前一个节点的删除事件
unlock方法就是删除子节点的过程,删除后,注册自己的后一个节点就会收到通知重新来执行lock方法
zookeeper集群
1.zk集群的特点:
1).可靠的zk服务
2).只要集群的大多数都准备好了,就可以使用这项服务
3).容错集群设置至少需要三个服务器,强烈建议使用奇数个服务器
4).建议每个服务运行在单独的机器上
2. zk集群搭建
1)配置项的说明
initLimit:集群中follower与leader之间初始化同步连接能容忍的最多心跳数(tickTime的倍数)
syncLimit:集群中的主节点与从节点之间请求应答之间能容忍的最多心跳数(tickTime的倍数)
server.id=host:port1:port2其中id是各自dataDir目录下创建一个名为myid的文件(myid文件只有一个数值内容,比如1,其值应该是集群唯一且1-255之间)为每台机器赋予一个服务器id
port1是follower用来连接到领导者, port2是用来选举领导者
例如server.1=127.0.0.1:2888:3888代表当前节点是第一个节点,这个1是通过myid文件指定,127.0.0.1是节点ip,2888用来连接到领导者,3888用来选举领导者
3.zk集群监控
jconsole监控(zk是java实现,是java程序运行)
4.ZAB协议
ZookeeperAtomicBroadcast(Zookeeper原子广播协议)
1.ZAB协议过程:
1).所有从节点接收到写请求,事务请求转发给leader
2).leader分配全局单调递增事务id(zxid),广播事务提议
3).follower处理提议,做出反馈(无脑同意)
4).leader收到板书反馈,广播commit
5).leader做出响应
2.ZAB协议--崩溃恢复
leader服务器出现崩溃,或者由于网络原因导致leader与过半follower失去联系,进入奔溃恢复模式
奔溃恢复的原则:
1).ZAB协议规定如果一个事务在一台机器上被处理成功,那么所有机器都被处理成功,即使机器出现故障崩溃
2).ZAB协议确保那些已经在leader上提交的事务最终被所有服务器提交
3).ZAB协议确保丢弃那些只在leader服务器上被提出(不是提交)的事务
奔溃恢复的机制:
1).选举新的leader一定是拥有最高zxid的节点,leader给一个follower准备一个队列,将follower没有同步的事务重新发送一次,包含proposal消息和commit消息;
2).follower接收到队列中的事务,全部处理完成,leader服务器就会将该follower加入可用follower列表,当超过半数节点完成数据同步,即可对外服务
举例说明这个流程:假如ABCDE五个节点,A节点为leader,当A宕机,若宕机时,已经发出的zxid最大为10,已发出未响应的zxid为11,选举新leader时,会看哪个节点的zxid最大,假如是B,那么B成为新leader,假设C最大zxid为8,那么为C创建的队列需要传输的内容包括8的proposal消息和8的commit消息以及9的proposal消息和8的commit消息,依次类推,当过半数节点同步完成,则对外开始服务;此时,若原来的leaderA恢复,会成为follower,发现自己最大是zxid=11,比leader还大,则丢弃11这个事务
5.Zxid是什么组成的
zxid是一个64位的数字
低32位是一个单调递增的技术器,针对客户端的每一个事务请求,leader服务器在提议一个新的事务proposl的时候,都会对该计数器+1
高32位代表了leader周期纪元的编号,每产生一个新的leader,都会从这个leader服务器上取出其本地日志中最大事务zxid,并从中解析出纪元值+1,并以此作为新的纪元号,同时,低32位以0开始重新计数
我的解读:高32位相当于是一个朝代号,每次换新leader就要创建一个新的朝代号,并且低32位要重新归零,相当于抹去上一个领导的所有痕迹哈哈哈哈哈,这样设计可以使得旧leader恢复时,发现朕的大清完了,然后自己以follower加入leader,同时,本地在上一个朝代最大的事务与leader事务日志中上一个朝代的最大事务对比,丢弃掉自己多余的事务.
6.zk的leader选举
6.1对选举的算法要求
6.1.1选出的leader节点上要持有最高的zxid
6.1.2超半数节点同意
6.2内置实现的选举算法
LeaderElection
FastLeaderElection(默认)
AuthFastLeaderElection
6.3选举机制中的概念
6.3.1服务器id myid文件中指定1-255
6.3.2事务id 服务器汇总存放的最大zxid
6.3.3发起投票轮数计数 如果在设置的时间内未选举出leader进入第二轮,此时收到第一轮的选票就丢弃
6.3.4选举状态包含
looking:竞选状态
following随从该状态,同步leader状态,参与投票
observing 观察状态,同步leader状态,不参与投票(当节点数比较多,可以指定几个节点参与投票,剩余就是不参与的)
leading领导者状态
6.4选举算法:
6.4.1每个服务实例均发起选举自己成为领导者的投票(自己先投给自己)
6.4.2其他服务实例收到投票邀请时,比较发起者的最大zxid是否比自己的最大zxid大,是则投票,否则不投票,若相等,比较对方的服务器id,大于自己,投票,否则不投票
6.4.3发起者收到大家的投票反馈后,看投票数是否大于集群的半数,是则成为leader,否则再次发起投票
举例说明启动时的选举流程
有五台服务器,他们id分别为1-5,大家都没有数据,zxid均是0,依次启动
1.服务1启动,发起投票,投给自己,由于其他机器没有启动,所以收不到反馈信息,此时处于looking状态
2.服务器2启动,发起投票,投给自己,向1拉票,因为id大于1,所以获得1的选票,因为选票未过半数,故而也是looking状态
3.服务器3启动,发起投票,投给自己,向12拉票,获得总票3,成功成为leader
4.服务4启动,发现已有leader成为小弟
5.同4流程