简介:
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,可以通过ZooKeeper进行统一命名服务、统一配置、集群管理、分布式锁理、负载均衡等,简单来说,Zookeeper=文件系统+监听通知机制。
为了便于理解,可以这么解读:1. ZK内部拥有一个树状的内存模型,每个节点称为znode,可以用来存储少量的节点数据,比如节
点路径以及关联的子节点列表;
2. 集群中如果某个服务器节点下线,不提供服务了,ZK可以将这类信息通知到所有监听了这个节点 的客户端,让它做对应的处理;
注意点
-
ZK与Nacos作为注册中心的区别:
ZK强调的是最终一致性(Consistency)与分区容错性(Partition tolerance),即CP,同样作为注册中心的Nacos是可用性(Availability)与分区容错性,即AP;
-
ZK的创建模式:
ZK是基于观察者模式的分布式服务管理框架;服务端存储一些重要的数据,接收客户端的注册,当服务端数据发生改变时,就通知监听这个服务端的客户端们做对应操作;
-
ZK中的角色
3.1 server(服务端)—请求处理方
- leader(领导者),负责发起投票,数据更新;
- follower(更随着),负责接收客户端请求,只处理读取操作,写操作转发给leader;参与选主投票;
- observer(观察者),类似folllower,但是不参与选主投票,主要为了防止多台服务器节点投票选举过程中因为节点数过多导致的选主耗时过长;
3.2 client(客户端)—请求发起方
-
ZK服务器工作状态
- LOOKING : 此时集群中没有leader,节点处于选举状态;
- LEADING:此时集群中产生leader,leader的状态就是LEADING;
- FOLLOWING:产生leader后,其余的跟随者follower就是FOLLOWING状态;
-
ZK读写机制
- ZK中leader处理写请求,follower处理读请求,每个follower、observer中保存一份数据副本,全局数据一致;
-
ZK的特性
- 所有的更新请求会顺序执行,并且通过一个递增的事务号(zxid)标记事务,zxid越大,说明该操作越新;
- 集群中所有节点数据全局一致,无论client访问哪一个节点,读取的数据都是一致的;
-
ZK集群数
ZK适合安装奇数台服务器,原因—集群中只要有半数以上的节点存活,就可以提供服务,5台中如果有2台挂掉,满足半数以上存货,集群依旧工作;如果变成4台,不满足,集群挂掉;如果是6台,可以工作,但是浪费了一台资源;
-
ZK工作原理
- ZK的核心是原子广播,并以此来保证各个服务器节点之间的数据同步。
- ZK原子广播机制的实现是基于Zab协议,Zab协议包括恢复模式与广播模式两种模式。
- 恢复模式,发生在服务启动或者leader宕机需要选主时,选主完成并且大多数follower与leader完成同步后,恢复模式结束。
- 广播模式,发生在大多数follower与leader数据同步,退出恢复模式后。此时如果新增一个server节点,会以恢复模式启动,发现leader并且完成数据同步后,退出恢复模式,参与消息广播。
- ZK中每台服务器启动后,其余服务器节点都会询问它要投票给谁,首次server都会投票给自己,只有再投票信息交换时,才会回复自己推荐的leader的id,并且将自身上一次处理事务的zxid(这很容易理解,我选出了主节点,但是当前我的事务操作可能时是最新的,所以,就算我失去了变成leader的机会,但是leader需要根据我最新的事务来以我的数据作为更新的数据源);
- leader根据follower发过来的zxid,以最新(即zxid的数字最大)的作为同步点;
下载及安装
下载
-
Zookeeper官网
2. 下载到本地,通过ftp上传到服务器
安装
-
解压到本地
//解压缩 -C解压到指定文件路径 tar -zvxf apache-zookeeper-3.5.7-bin.tar.gz -C /www/
-
修改配置文件(此处重点,避免踩坑)
dataDir=/www/server/zookeeper-3.5.7/zkData //配置自己创建的文件路径,不要用默认的临时文件路径 admin.serverPort=8089 //配置服务端启动端口
此处需要注意,如果不配置这边的启动端口,启动服务端的时候会报错:it is probably running;查看logs文件夹下的.out日志文件,发现是端口占用异常。
启动
-
启动服务端
[root@47 zookeeper-3.5.7]# bin/zkServer.sh start //启动服务端
-
查询服务端启动状态
[root@47 zookeeper-3.5.7]# bin/zkServer.sh status /usr/bin/java ZooKeeper JMX enabled by default Using config: /www/server/zookeeper-3.5.7/bin/../conf/zoo.cfg Client port found: 2181. Client address: localhost. Mode: standalone //本地运行状态
-
启动客户端
[root@47 zookeeper-3.5.7]# bin/zkCli.sh
-
退出客户端
[zk: localhost:2181(CONNECTED) 1] quit
-
退出服务端
[root@47 zookeeper-3.5.7]# bin/zkServer.sh stop /usr/bin/java ZooKeeper JMX enabled by default Using config: /www/server/zookeeper-3.5.7/bin/../conf/zoo.cfg Stopping zookeeper ... STOPPED [root@47 zookeeper-3.5.7]#
ZK执行流程
ZK写请求流程
- 第一步:客户端client1发起写入请求;
- 第二步:follower接收写请求,转发给leader;
- 第三步:leader发起写入投票;
- 第四步:汇总投票结果,并且将结果发送给leader;
- 第五步:leader根据投票结果,判断当前投票数是否过半;
- 第六步:如果超半数,则进行写入,并且把 将写入操作通知到follower,最后提交事务;
- 第七步:follower将请求返回给client;
ZK选主流程(以5个节点为例)
前提了解:
1. zxid,事务的标识,每次写操作都会生成一个自增的事务id,数据越大说明数据越新;
2. myid,即serverId,可通过配置文件配置,服务编号,编号越大,权重越大;
3. epoch,leader的任期标识,可以理解为:每一个新的leader产生,都会生成一个新的epoch,就好比,古代每个皇帝老儿登基的适合都有自己的年号~
- 第一步,集群中第一个服务器节点上线,进行选举投票(投自身一票),但是不满足超过半数以上节点存活,所以选主未完成,server-1状态保持looking;
- 第二步:集群中第二个节点上线,进行选主投票(同样投自己),并且与server-1交换投票信息:首先比较各自的zxid,初始化各个节点的zxid值相同,然后比较myid,发现server-2的权重比较大,server-1将选票投给server-2,此时server-1选票为0,server-2选票为2,但此时依旧不满足半数以上存货,所以选主还未完成,两个服务器状态依旧是looking;
- 第三步:集群中第三个节点上线,进行选主投票,继续投给自己。紧接着继续交换各自的选票信息,server-1与server-2发现myid都小于server-3,此时,选票全都投给server-3,此时集群中3台服务器存活,满足超半数以上存活,server-3暂时选举成功变成leader,状态变为leading,其余变为following;
- 第四步:集群中第四个服务器节点上线,发起选主投票,自身获得1票。但是因为其余三个节点的状态已经不是looking,所以不会交换投票信息,所以最终server-4的票数为1,小于server-3,server-4变成follower,变成小弟,状态改成following;
- 后续:此时第五台服务器节点上线,会重复第四步的选主操作,直至最终全部节点上线,server-3变成最终的leader;
注意:
非第一次启动时,会根据epcoh->zxid->myid这个顺序来比较选举leader;