什么是zookeeper?
是一个解决分布式集群中应用系统一致性问题的一个分布式协调服务框架,本质是一个分布式的小文件存储系统,提供给客户端监控存储在zk内部数据的功能
主要的应用场景:
- 服务注册与订阅(共用节点)
- 分布式通知(监听znode)
- 服务命名(znode特性)
- 数据订阅、发布(watcher)
- 分布式锁(临时节点)
zookeeper架构组成
zookeeper的三个角色
leader:核心组件,事务(写)请求的唯一请求
follow:处理非事务(读)请求,转发事务请求到leader,并且参与leader的选举
observer:观察者角色,观察zookeeper集群的的最新状态并同步状态,对于非事务请求可独立请求,对于事务请求则会转发给leader。并且不会参与任何形式的投票,通常用于不影响集群事务处理能力的前提下提升集群的非事务处理能力,增加集群的并发的读请求
zookeeper特点
- 一个leader多个follow有的还有observer观察者
- leader负责内部选举的发起和决议,更新系统状态
- Follower用于接收客户请求并向客户端返回结果,在选举Leader过程中参与投票
- 集群中有半数以上节点存活,ZK集群就能正常服务
- 全局数据一致,每个server都保存一份相同的数据副本,Client无论连接到哪个server,数据都是一致的(可以理解为每个follower存储的数据都是leader存储数据的副本)
- 更新请求顺序进行
- 数据更新原子性,要么都成功要么都失败
Zookeeper数据模型Znode
在ZK中,数据信息保存在一个个数据节点上,这些节点被称为znode,是ZK中的最小数据单位。而在ZNode下还有再有ZNode,于是就形成了一个树形结构,我们称之为ZNode Tree
ZNode的类型
- 持久性节点(Persistent)
- 临时性节点(Ephemeral)
- 顺序性节点(Sequential)
故在创建节点的时候通过组合可以生成四种节点类型:持久节点、持久顺序节点、临时节
点、临时顺序节点。
持久节点:最常用。持久节点就是该节点被创建后会一直存在服务器上,直到执行删除操作才会进行清除
临时节点:会自动清理掉的节点。生命周期和客户端会话绑定在一起。客户端会话一结束,节点就会被删除掉,与持久节点不同的是临时节点不能创建子节点
持久顺序节点:就是有顺序的持久节点,实质是在创建节点的时候会在节点名后面加上一个数字后缀,表示其顺序。
临时顺序节点:就是有顺序的临时节点,也是会在创建节点的时候会在节点名后面加上一个数字后缀。
事务ID
在ZK中事务指的是能够改变ZK服务器状态的操作(create,update data,更新子节点),也称之为事务操作或更新操作。
一般包括数据节点创建与删除,数据节点内容更新等操作。
对于每一个事务请求,ZK都会为其分配一个全局唯一的事务ID(ZXID表示,通常是一个64位的并且是自增长的数字),每一个ZXID对应一个更新操作,通过ZXID就能间接地识别出ZK处理这些更新操作请求的全局顺序
ZNode的状态信息
黄色荧光笔位置为内容信息,此节点的内容为空
Watch机制(监听机制)
ZK使用Watcher机制实现分布式数据的发布/订阅功能
Zookeeper的Watcher机制主要包括客户端线程、客户端WatcherManager、Zookeeper服务器三部分。
在 ZooKeeper 中,引入了 Watcher 机制来实现这种分布式的通知功能。ZooKeeper 允许客户端向服务端注册一个 Watcher 监听,当服务端的一些指定事件触发了这个 Watcher,那么Zk就会向指定客户端发送一个事件通知来实现分布式的通知功能。整个Watcher注册与通知过程如图所示。
具体流程:
当客户端向ZK服务器注册的同时会将Watcher对象存储在客户端的WatcherManager当 中,当ZK服务器触发Watcher事件后,会向客户端发送通知,客户端线程WatcherManager中取出对应的Watcher对象来执行回调逻辑
选举机制:
-
半数机制,即集群中半数以上的机器存活,集群就可用,故ZK适合安装奇数台服务器
-
其虽没在配置文件中指定Master和Slave,但在ZK工作时会通过内部的选举机制产生一个leader,其余均为follower
集群首次启动流程
(1)服务器1启动,开始选举,因为此时只有他自己,发出去的请求报文没有得到反馈,所以他的选举状态一直是寻找leader的状态(即LOOKING状态)但会把票投给自己
(2)服务器2启动,发现服务器中没有leader,于是开始投票选举leader,此时与已经启动的服务器1通信,互相交换选举结果,所以id值较大的服务器2获胜,此时服务器1也会把票投给比自己大的服务器2。但是由于没有达到超过半数以上的服务器都同意选举它,所以服务器1、2还是继续保持LOOKING状态。
(3)服务器3启动,他依旧会投自己,此时服务器1和服务器2发现服务器3大,于是服务器1和服务器2改票,都投服务器3。此时服务器3有三张选票,超过了半数,成为了此时选举的leader
(4)服务器4,5启动,虽然id值比之前的都大。由于已经有leader产生,故只能当小弟(follower)
总结:leader选举的最终结果于服务器id值有关系,服务器的启动顺序有关系,还与是否超过集群半数有关系。
集群非首次启动
会优先选择zxid(事务ID)值大的节点称为leader
ZAB一致性协议
(ZAB,Zookeeper原子消息广播协议)是为ZK专门设计的一种支持崩溃恢复和原子广播协议,用于保持数据一致性的算法
主备模式保持一致性
因为所有客户端写入数据最终都是要写入leader中,然后由leader复制到follower中。ZAB协议会将服务器数据的状态变更以事务Proposal的形式广播到所有的副本上,ZAB协议能够保证了事务操作的一个全局的变更序号(ZXID)。
广播消息
客户端发送的写请求被leader接收之后,leader会将其封装为一个事务Proposal(提议),每个事务Proposal会有一个ZXID,随后leader会将其发送给follower进行投票。follower接受到Proposal之后会解析出要做什么操作,并且会校验ZXID,其不能小于上次事务请求的ZXID。leader会等待follower发送ACK(即同意的意思,提议通过),如果超过半数反馈ACK,则执行Commit操作(先提交自己,再发送 Commit 给所有 Follwer)。
详细步骤图解
1.发送Proposal到Follower
2.Leader接收Follower的ACK
3.超过半数ACK则Commit
发送commit到follower,同时自己commit
其中不能正常反馈Follower恢复正常后会进入数据同步阶段最终与Leader保持一致!!
总结:
- leader接受到客户端请求之后,会将请求封装成一个事务,并为事务分配一个ZXID,因ZAB要求事务的顺序,因此必须将每一个事务按照ZXID进行排序然后处理
- ZK集群为保证事务操作能有序的顺序执行,只能leader接受写请求,即使follower接受到客户端的请求,也会转发到leader服务器处理
leader崩溃问题
Leader宕机后,ZK集群无法正常工作,ZAB协议提供了一个高效且可靠的leader选举算法
这个算法的关键就是:保证选举出的新leader拥有集群中所有节点最大编号(ZXID)的事务
启动:
进入到zookeeper的bin目录之后
./zkcli.sh 连接本地的zookeeper服务器
./zkCli.sh -server ip:port(2181) 连接指定的服务器
获取节点的状态信息: get /zookeeper
查看节点的子节点:ls /zookeeper
ZK命令行操作
连接本地的zookeeper服务器 :进入到ZK的bin目录下执行 ./zkcli.sh
连接指定的服务器 :进入到ZK的bin目录下执行 ./zkCli.sh -server ip:port(2181)
创建节点
create [-s][-e] path data
其中,-s或-e分别指定节点特性,顺序或临时节点,若不指定,则创建持久节点
- 创建顺序节点: create -s /zk-test 123
- 创建临时节点: create -e /zk-test 123
- 创建永久节点: create /zk-test 123
读取节点
- ls命令可以列出Zookeeper指定节点下的所有子节点,但只能查看指定节点下的第一级的所有子节点;
ls path
其中,path表示的是指定数据节点的节点路径
获取根节点下的所有子节点:ls /
- get命令可以获取Zookeeper指定节点的数据内容和属性信息。
get path
例如:get /zookeeper 获取zookeeper节点的相关信息
更新节点
使用set命令,可以更新指定节点的数据内容,用法如下
set path data
例如:set /zk-permanent 456 将/zk-permanent节点的数据更新为456
删除节点
使用delete命令可以删除Zookeeper上的指定节点,用法如下
delete path
例如:delete /zk-permanent 删除/zk-permanent节点
注意:若删除节点存在子节点,那么无法删除该节点,必须先删除子节点,再删除父节点
退出客户端命令:quit