一、概述
1.1、Zookeeper的作用:
Zookeeper是高性能的分布式协作服务和分布式数据一致性解决方案,解决分布式文件系统中的一些业务协调问题。其底层的一致性就是用Paxos算法为基础的。
Paxos算法:一种基于消息传递并且具有高度容错性的一致性算法。决议只有被提议者提出之后才能被批准,一次算法执行过程中,只能有一个决议,学习者只能获得被批准的决议
Paxos算法了解推荐链接,点击该处自动转跳
其中有三个角色
提议者Proposer:用来发出提案
接受者Acceptor:可以接收或者拒绝提案
学习者Learner:学习被选定的提案
ZK作为一个集群提供数据一致性的协调服务,最好的方法就是在集群中的各个服务节点进行数据的复制和备份
数据复制的好处:
- 容错:单个或几个节点出错,不至于让整个集群无法提供服务
- 扩展性:通过增加服务器节点可以提高ZK系统的负载能力,把负载分布到多个节点上
- 高性能:客户端可以访问本地ZK节点或就近访问附近的节点,以此提高用户的访问速度
1.2、Zookeeper特点:
- 最终一致性:client不论连接到哪个Server,展示给client的都是同一个视图,这是ZK最重要的特性
- 可靠性:具有简单,健壮,良好的性能,如果消息M被一台服务器接收,那么它将被所有的服务器接收
- 实时性:ZK保证客户端在一个时间间隔范围内获得服务器的更新信息,或者服务器失效的信息。但由于网络延时等原因,ZK不能保证两个客户端能同时得到刚更新的数据,如果需要最新数据,应在读数据之前调用sync()接口
- 等待无关(wait-free):慢的或者失效的client不得干预快速的client的请求,使得每个cilent都能有效的等待
- 原子性:更新只能成功和失败,没有中间状态
- 顺序性:包括全局有序和偏序两种,全局有序指如果在一台服务器上消息a在消息b之前发布,则所有Server上消息a都将在消息b前被发布,偏序是指如果一个消息b在消息a后被同一个发送者发布,a必将排在b前面
1.3、Zookeeper结构
1.3.1、文件系统:
Zookeeper的命名空间就是ZooKeeper应用的文件系统,它也是树状的,与Linux的文件系统不同,linux文件系统有目录和文件,ZooKeeper统一叫Znode
(1)每个Znode节点既可以存储数据,也可以挂载子节点
(2)Znode只能存储小量的数据(不能超过1M,最好小于1K),适合存储小量的关键性数据
(3)每个节点都有一个唯一的路径标识,不存在相对路径
关于Znode的介绍:
- Znode有两种类型:
短暂(ephemeral)
持久(persistent) - Znode节点(默认persistent)
(1) 不带序列号的临时节点(ephemeral):
临时创建的,会话结束时会被自动删除,临时节点无法挂载子节点
(2) 带序列号的临时节点(ephemeral_sequential)
比临时节点多了序列号,分布式锁中会用到该节点
(3)不带序列号的持久节点(persistent)
创建后永久存在,除非手动删除
(4)带序列号的持久节点(persistent_sequential)
比持久节点多了一个10位数字的序列号。如果序列号大于2^32就会溢出
create -s /Znode_name “data” //-e参数为创建临时节点,不带该参数则创建持久节点,-s参数为创建顺序节点
- 创建Znode时设置顺序标识,Znode名称后会附加一个值,顺序号是一个单调递增的计数器,由父节点维护
- 在分布式系统中,顺序号可以被用于为所有的事件进行全局排序,这样客户端就可以通过顺序号推断事件的顺序
- 客户端可以在Znode上设置监听器
1.3.2监听机制
-
三个重要组成部分:
客户端线程
客户端WatchManager:管理所有的Watcher
ZooKeeper服务器 -
作用:
客户端注册监听它关心的Znode节点,当Znode节点发生变化时,ZK会通知客户端,监听机制保证ZK保存的任何数据的任何改变都可以快速的响应到监听了该节点的应用程序 -
实现:
客户端在向Zookeeper服务器注册的同时,会将Watcher对象存储在客户端的WatcherManager中,当ZooKeeper服务器触发Watcher事件后,会向客户端发送通知,客户端线程从WatchManager中取出对应的Watcher对象来执行回调逻辑
拿链接,ZK系统等待相关节点的相关事件发生,之后通知客户端,客户端收到通知后自动调用回调代码
1.4、典型应用场景
1.4.1、命名服务
通过命名服务,客户端可以根据指定名字来获取资源的实体、服务地址和提供者的信息。即按名称表示集群中的节点
创建了一个文件或者文件夹,就算是完成了一次命名服务
1.4.2、配置管理
程序往往需要配置,如果是在分布式集群中,要逐个修改配置就会很繁琐。我们可以把所有的配置信息放到ZK上去,将这些配置信息保存在ZK的某个Znode节点中。之后所有的相关应用程序对这个Znode节点进行监听,一旦配置信息发生变化,每个应用程序就会收到ZK的通知,之后从ZK中获取新的配置信息到系统中
1.4.3、集群管理
是否有机器加入或退出集群,选举leader
1.4.4、分布式锁
锁分为以下三类:
- 写锁,对写加锁,保持独占,也叫排它锁,独占锁
- 读锁,对读加锁,可共享访问,释放锁之后才可进行实务操作,也叫共享锁
- 时序锁,控制时序
1.4.5、队列管理
队列类型:
- 同步队列:当一个队列的成员都聚齐时,这个队列才可用,否则一直等待所有成员到达
- 先进先出队列(FIFO):队列按照FIFO方式进行入队和出队操作
1.5、注意事项
启动ZK之前关闭防火墙或者配置安全组策略
systemctl status firewalld.service
停止防火墙命令 systemctl stop firewalld
开机禁止启动命令 systemctl disable firewalld
集群中的selinx关闭
getenforce: disabled : 已经关闭
setenforce 0 临时关闭
vim /etc/selinux/config
改为disabled
1.6、ZooKeeper的命令行操作
首先,我们可以通过zkCli.sh进入ZK的命令行客户端,该方式直接连接本机的ZK服务器,也可以使用zkCli.sh -server ip:2181 连接其他的服务器。
命令 | 作用 |
---|---|
ls / | 查看Znode子节点内容 |
create /zk “data” | 创建znode节点,内容是"data" |
get /zk | 获取zk节点的数据 |
set /zk “data2” | 设置zk的数据为"data2" |
ls /zk watch | 对一个节点的子节点变化事件注册了监听 |
get /zk watch | 对一个节点的数据内容变化事件注册了监听 |
create -e /zk “data” | 创建临时Znode节点 |
create -s /zk “data” | 创建顺序Znode节点 |
delete /zk | 删除没有子Znode的Znode |
rmr /zk | 无论有没有子Znode,统统删除 |
1.7、ZooKeeper原理
1.7.1、集群角色描述
角色 | 描述 |
---|---|
领导者(Leader) | Leader负责进行投票的发起和决议,更新系统状态 |
跟随者(Follower) | Follower用于接受客户端请求并向客户端返回结果,在选主过程中参与投票 |
观察者(ObServer) | ObServer可以接受客户端连接,将写请求转发给Leader节点,但其不参与投票,只同步Leader状态 |
客户端(Client) | 请求发起方 |
ObServer和Follower都是Learner(学习者),出来ObServer没有选举权和被选举权之外,他俩几乎一样。**其存在目的是在ZK的压力过大时进行压力分担
1.7.2、Leader的选举
ZooKeeper server的三种工作状态:
LOOKING:当前Server不知道Leader是谁,正在搜寻,正在选举
LEADING:当前Server即为选举出来的Leader,负责协调事务
FOLLOWING:Leader最近选举出来,当前Server与之同步,服从Leader命令
- ZK的全新集群选Leader
假设5台服务器组成ZK集群,它们的serverid从1-3,同时它们都是没有历史数据的,如果他们依序启动
(1)服务器1启动,此时只有它一台服务器启动,他发出去的通讯没有响应,所以它的选举状态一直为LOOKING
(2)服务器2启动,它与服务器1进行通讯,交换自己的选举结果,由于两者都没有历史数据,所以id值较大的服务器2胜出,但是由于没有超过半数(3)的服务器都同意选举他,所以服务器1、2还是继续保持LOOKING状态
(3)服务器3启动,由前面可得,服务器3的serverid最大,所以服务器3胜出,而此时集群中已经都3台服务器选举了它,所以它成为了这次选举的Leader
(4)服务器4启动,虽然服务器4的serverid最大,但由于之前已经有半数以上的服务器选择了服务器3,所以服务器4只能当Follower
(5)同上
- ZK的非全新集群选主
当ZK集群运行一段时间后,有机器挂掉了,需要从新选举时,需要加入数据version,serverid和逻辑时钟三个东西。
数据version:数据每次更新都会更新version,新的数据version就比较大
serverid:即配置的myid的值,每个机器一个
逻辑时钟:这个值从0开始递增,每次选举对应一个值。即在同一次选举中,这个值一个是一致的,如果这个值越大,说明这一次选举Leader的进程更新,即每次选举拥有一个zxid,投票结果只取zxid最新的。
(1)逻辑时钟小的选举结果被忽略,从新投票
(2)统一逻辑时钟后,数据version大的胜出
(3)前两者无法选举出Leader的时候,serverid大的胜出。
1.7.3、数据同步
选举完Leader之后,zk就进入状态同步的过程
- Leader等待server连接
- Follower连接Leader,将最大的zxid发给leader
- leader根据follower的zxid确定同步点
- 完成同步通知follower已经变成了uptodate状态
- follower收到uptodate消息后,又可以从新接受client的请求进行服务了
1.7.4、工作流程
- Leader工作流程
Leader主要有三个功能:
(1)恢复数据
(2)维持与Learner的心跳,接受Learner请求并判断Learner的请求消息类型
(3)根据不同的消息类型,进行不同的处理
Learner的消息类型:
PING消息:Learner的心跳信息
REQUSET消息:Follower发送的提议信息,包括读写请求
ACK消息:Follower对提议回复,超过半数Follower通过,则commit该提议
REVALIDATE消息:延长session有效时间
- Follower工作流程
(1)向Leader发送消息
(2)接收Leader消息并进行处理
(3)接收Client的请求,如果是写请求,则转发给Leader
(4)返回Client的结果
Follower的消息循环处理如下几种来自Leader的消息:
PING消息:心跳消息
PROPOSAL消息:Leader发起的提案,要求Follower投票
COMMIT消息:服务器端最新一次提案的消息
UPTODATE消息:表明同步完成
REVALIDATE消息:根据Leader的REVALIDATE结果,关闭待revalidate的session还是允许其接受消息
SYNC消息:返回SYNC结果到客户端,这个消息最初由客户端发起的,用来强制得到最新的更新
- Observer工作流程
除了不参与Leader发起的投票,也不会被选举为Leader,其他都和Follower一样。
1.8、ZooKeeper架构
ZK是主从架构。主节点挂掉之后需要从新选举一个Leader,即意味着所有节点的状态必须时刻保持一致。所以每个ZK节点都要保存一份完整的Znode数据。所以任何一个非Leader节点收到写数据请求时,都会将请求转发到Leader节点,之后Leader节点通过ZAB(原子广播协议)控制系统的全局事务。
最终效果:成功接收到Leader节点的同步数据请求,顺序更改掉数据的值。
没有接受成功的节点,不让其对外提供服务。