Zookeeper:一个用于分布式应用程序的分布式,开源的协调服务
ZooKeeper 公开了一组简单的原语,分布式应用程序可以基于这些原语来实现统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等
简单来说 ZooKeeper = 文件系统 + 监听通知机制
1.文件系统
ZooKeeper维护一个类似于文件系统的数据结构:
每个子目录项如 NameService 都被称作 znode(目录节点),和文件系统一样,我们能够自由的增加、删除 znode,在一个 znode 下增加、删除子 znode,唯一的不同在于 znode 是可以储存数据的。
有四种类型的 znode:
- PERSISTENT-持久化目录节点
客户端与zookeeper断开连接后,该节点依旧存在 - PERSISTENT_SEQUENTIAL-持久化顺序编号目录节点
客户端与zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号 - EPHEMERAL-临时目录节点
客户端与zookeeper断开连接后,该节点被删除 - EPHEMERAL_SEQUENTIAL-临时顺序编号目录节点
客户端与zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号
2.监听通知机制
客户端注册监听它关心的目录节点,当目录节点发生变化(数据改变、被删除、子目录节点增加删除)时,zookeeper 会通知客户端。
ZooKeeper单机模式配置安装
配置文件
1 | tickTime=2000 |
- tickTime:ZooKeeper使用的基本时间单位(毫秒)。它用于做心跳,并且最小会话超时将是tickTime的两倍
- dataDir:存储内存数据库快照的位置,除非另有说明,否则存储数据库更新的事务日志。
- clientPort:用于监听客户端连接的端口
简单操作
启动命令:zkServer.sh start
命令行连接:zkCli.sh
- 使用
ls命令来查看当前 ZooKeeper 中所包含的内容ls \ - 创建一个新的 znode ,使用
create /zkPro myData - 使用
get命令来查看上面创建的znode中是否存在对应的数据get /zkPro - 使用
set命令来对zk索关联的字符串进行设置:set /zkPro myData123 - 删除znode:
delete /zkPro
分布式搭建
三台机器
配置文件
1 | server.1=xxx.xxx.xxx.xxx:2888:3888 |
添加如下配置,启动即可,需要在data路径下添加 myid 文件配置id
Zookeeper 的 Leader 选举
Leader选举是保证分布式数据一致性的关键所在。Leader选举分为Zookeeper集群初始化启动时选举和Zookeeper集群运行期间Leader重新选举两种情况。
1、Zookeeper节点状态
- LOOKING:寻找Leader状态,处于该状态需要进入选举流程
- LEADING:领导者状态,处于该状态的节点说明是角色已经是Leader
- FOLLOWING:跟随者状态,表示Leader已经选举出来,当前节点角色是follower
- OBSERVER:观察者状态,表明当前节点角色是observer,可以接受客户端连接,将写请求转发给leader,但observer不参加投票过程,只同步leader的状态,observer的目的是为了扩展系统,提高读取速度
2、事务ID
ZooKeeper状态的每次变化都接收一个ZXID(ZooKeeper事务id)形式的标记。ZXID是一个64位的数字,由Leader统一分配,全局唯一,不断递增。
ZXID展示了所有的ZooKeeper的变更顺序。每次变更会有一个唯一的zxid,如果zxid1小于zxid2说明zxid1在zxid2之前发生。
3、Zookeeper集群初始化启动时Leader选举
若进行Leader选举,则至少需要两台机器,这里选取3台机器组成的服务器集群为例。
初始化启动期间Leader选举流程如下描述
在集群初始化阶段,当有一台服务器ZK1启动时,其单独无法进行和完成Leader选举,当第二台服务器ZK2启动时,此时两台机器可以相互通信,每台机器都试图找到Leader,于是进入Leader选举过程。选举过程开始,过程如下:
- 每个Server发出一个投票。由于是初始情况,ZK1和ZK2都会将自己作为Leader服务器来进行投票,每次投票会包含所推举的服务器的myid和ZXID,使用(myid, ZXID)来表示,此时ZK1的投票为(1, 0),ZK2的投票为(2, 0),然后各自将这个投票发给集群中其他机器。
- 接受来自各个服务器的投票。集群的每个服务器收到投票后,首先判断该投票的有效性,如检查是否是本轮投票、是否来自LOOKING状态的服务器。
- 处理投票。针对每一个投票,服务器都需要将别人的投票和自己的投票进行比较,规则如下
- 优先检查ZXID。ZXID比较大的服务器优先作为Leader。
- 如果ZXID相同,那么就比较myid。myid较大的服务器作为Leader服务器。
对于ZK1而言,它的投票是(1, 0),接收ZK2的投票为(2, 0),首先会比较两者的ZXID,均为0,再比较myid,此时ZK2的myid最大,于是ZK2胜。ZK1更新自己的投票为(2, 0),并将投票重新发送给ZK2。
- 统计投票。每次投票后,服务器都会统计投票信息,判断是否已经有过半机器接受到相同的投票信息,对于ZK1、ZK2而言,都统计出集群中已经有两台机器接受了(2, 0)的投票信息,此时便认为已经选出ZK2作为Leader。
- 改变服务器状态。一旦确定了Leader,每个服务器就会更新自己的状态,如果是Follower,那么就变更为FOLLOWING,如果是Leader,就变更为LEADING。当新的Zookeeper节点ZK3启动时,发现已经有Leader了,不再选举,直接将直接的状态从LOOKING改为FOLLOWING。
4、Zookeeper集群运行期间Leader重新选
在Zookeeper运行期间,如果Leader节点挂了,那么整个Zookeeper集群将暂停对外服务,进入新一轮Leader选举。
假设正在运行的有ZK1、ZK2、ZK3三台服务器,当前Leader是ZK2,若某一时刻Leader挂了,此时便开始Leader选举。选举过程描述。
- 变更状态。Leader挂后,余下的非Observer服务器都会讲自己的服务器状态变更为LOOKING,然后开始进入Leader选举过程。
- 每个Server会发出一个投票。在运行期间,每个服务器上的ZXID可能不同,此时假定ZK1的ZXID为124,ZK3的ZXID为123;在第一轮投票中,ZK1和ZK3都会投自己,产生投票(1, 124),(3, 123),然后各自将投票发送给集群中所有机器。
- 接收来自各个服务器的投票。与启动时过程相同。
- 处理投票。与启动时过程相同,由于ZK1事务ID大,ZK1将会成为Leader。
- 统计投票。与启动时过程相同。
- 改变服务器的状态。与启动时过程相同。