Java大型互联网架构-分布式系统服务框架Zookeeper介绍与原理实现

CobingLiu 2019-11-05

分布式系统服务框架Zookeeper介绍与原理实现

Zookeeper基本概念

zk角色

Zookeeper中的角色主要有以下三类,如下表所示:

Java大型互联网架构-分布式系统服务框架Zookeeper介绍与原理实现

zookeeper角色

zk service网络结构

Zookeeper的工作集群可以简单分成两类,一个是Leader,唯一一个,其余的都是follower,如何确定Leader是通过内部选举确定的。

Java大型互联网架构-分布式系统服务框架Zookeeper介绍与原理实现

zookeeper服务

Leader和各个follower是互相通信的,对于zk系统的数据都是保存在内存里面的,同样也会备份一份在磁盘上。

对于每个zk节点而言,可以看做每个zk节点的命名空间是一样的,也就是有同样的数据。(可查看下面的树结构)

如果Leader挂了,zk集群会重新选举,在毫秒级别就会重新选举出一个Leaer。

集群中除非有一半以上的zk节点挂了,zk service才不可用。

zk命名空间结构

Zookeeper的命名空间就是zk应用的文件系统,它和linux的文件系统很像,也是树状,这样就可以确定每个路径都是唯一的,对于命名空间的操作必须都是绝对路径操作。与linux文件系统不同的是,linux文件系统有目录和文件的区别,而zk统一叫做znode,一个znode节点可以包含子znode,同时也可以包含数据。

Java大型互联网架构-分布式系统服务框架Zookeeper介绍与原理实现

zookeeper树结构

提示:

比如/Nginx/conf,/是一个znode,/Nginx是/的子znode,/Nginx还可以包含数据,数据内容就是所有安装Nginx的机器IP,/Nginx/conf是/Nginx子znode,它也可以包含内容,数据就是Nginx的配置文件内容。在应用中,我们可以通过这样一个路径就可以获得所有安装Nginx的机器IP列表,还可以获得这些机器上Nginx的配置文件。

zk读写数据

Java大型互联网架构-分布式系统服务框架Zookeeper介绍与原理实现

zookeeper读写数据

写数据,但一个客户端进行写数据请求时,会指定zk集群中节点,如果是follower接收到写请求,就会把请求转发给Leader,Leader通过内部的Zab协议进行原子广播,直到所有zk节点都成功写了数据后(内存同步以及磁盘更新),这次写请求算是完成,然后zk service就会给client发回响应

读数据,因为集群中所有的zk节点都呈现一个同样的命名空间视图(就是结构数据),上面的写请求已经保证了写一次数据必须保证集群所有的zk节点都是同步命名空间的,所以读的时候可以在任意一台zk节点上

ps:其实写数据的时候不是要保证所有zk节点都写完才响应,而是保证一半以上的节点写完了就把这次变更更新到内存,并且当做最新命名空间的应用。所以在读数据的时候可能会读到不是最新的zk节点,这时候只能通过sync()解决。这里先不考虑了,假设整个zk service都是同步meta信息的,后面的文章再讨论。

zk znode类型

Zookeeper中znode的节点创建时候是可以指定类型的,主要有下面几种类型。

PERSISTENT:持久化znode节点,一旦创建这个znode点存储的数据不会主动消失,除非是客户端主动的delete。

SEQUENCE:顺序增加编号znode节点,比如ClientA去zk service上建立一个znode名字叫做/Nginx/conf,指定了这种类型的节点后zk会创建/Nginx/conf0000000000,ClientB再去创建就是创建/Nginx/conf0000000001,ClientC是创建/Nginx/conf0000000002,以后任意Client来创建这个znode都会得到一个比当前zk命名空间最大znode编号+1的znode,也就说任意一个Client去创建znode都是保证得到的znode是递增的,而且是唯一的。

EPHEMERAL:临时znode节点,Client连接到zk service的时候会建立一个session,之后用这个zk连接实例创建该类型的znode,一旦Client关闭了zk的连接,服务器就会清除session,然后这个session建立的znode节点都会从命名空间消失。总结就是,这个类型的znode的生命周期是和Client建立的连接一样的。比如ClientA创建了一个EPHEMERAL的/Nginx/conf0000000011的znode节点,一旦ClientA的zk连接关闭,这个znode节点就会消失。整个zk service命名空间里就会删除这个znode节点。

PERSISTENT|SEQUENTIAL:顺序自动编号的znode节点,这种znoe节点会根据当前已近存在的znode节点编号自动加 1,而且不会随session断开而消失。

EPHEMERAL|SEQUENTIAL:临时自动编号节点,znode节点编号会自动增加,但是会随session消失而消失

Zookeeper设计目的

最终一致性:client不论连接到哪个Server,展示给它都是同一个视图,这是zookeeper最重要的性能。

可靠性:具有简单、健壮、良好的性能,如果消息m被到一台服务器接受,那么它将被所有的服务器接受。

实时性:Zookeeper保证客户端将在一个时间间隔范围内获得服务器的更新信息,或者服务器失效的信息。但由于网络延时等原因,Zookeeper不能保证两个客户端能同时得到刚更新的数据,如果需要最新数据,应该在读数据之前调用sync()接口。

等待无关(wait-free):慢的或者失效的client不得干预快速的client的请求,使得每个client都能有效的等待。

原子性:更新只能成功或者失败,没有中间状态。

顺序性:包括全局有序和偏序两种:全局有序是指如果在一台服务器上消息a在消息b前发布,则在所有Server上消息a都将在消息b前被发布;偏序是指如果一个消息b在消息a后被同一个发送者发布,a必将排在b前面。

Zookeeper工作原理

Zookeeper 的核心是广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议。

Zab协议有两种模式,它们分别是恢复模式(选主)和广播 模式(同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和leader的状态同步以后, 恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。为了保证事务的顺序一致性,zookeeper采用了递增的事务id号 (zxid)来标识事务。所有的提议(proposal)都在被提出的时候加上了zxid。实现中zxid是一个64位的数字,它高32位是epoch用 来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的统治时期。低32位用于递增计数。

每个Server在工作过程中有三种状态:

LOOKING:当前Server不知道leader是谁,正在搜寻。

LEADING:当前Server即为选举出来的leader。

FOLLOWING:leader已经选举出来,当前Server与之同步。

选主流程

leader崩溃或者leader失去大多数的follower,这时候zk进入恢复模式,恢复模式需要重新选举出一个新的leader,让所有的 Server都恢复到一个正确的状态。

Zookeeper的选举算法有两种:

一种是基于basic paxos实现的,另外一种是基于fast paxos算法实现的。

系统默认的选举算法为fast paxos。

basic paxos流程:

选举线程由当前Server发起选举的线程担任,其主要功能是对投票结果进行统计,并选出推荐的Server;

选举线程首先向所有Server发起一次询问(包括自己);

选举线程收到回复后,验证是否是自己发起的询问(验证zxid是否一致),然后获取对方的id(myid),并存储到当前询问对象列表中,最后获取对方提议的leader相关信息(id,zxid),并将这些信息存储到当次选举的投票记录表中;

收到所有Server回复以后,就计算出zxid最大的那个Server,并将这个Server相关信息设置成下一次要投票的Server;

线程将当前zxid最大的Server设置为当前Server要推荐的Leader,如果此时获胜的Server获得n/2 + 1的Server票数, 设置当前推荐的leader为获胜的Server,将根据获胜的Server相关信息设置自己的状态,否则,继续这个过程,直到leader被选举出来。通 过流程分析我们可以得出:要使Leader获得多数Server的支持,则Server总数必须是奇数2n+1,且存活的Server的数目不得少于 n+1.每个Server启动后都会重复以上流程。在恢复模式下,如果是刚从崩溃状态恢复的或者刚启动的server还会从磁盘快照中恢复数据和会话信 息,zk会记录事务日志并定期进行快照,方便在恢复时进行状态恢复。

选举的具体流程图如下所示:

Java大型互联网架构-分布式系统服务框架Zookeeper介绍与原理实现

zk basic paxos选举

fast paxos流程:

在选举过程中,某Server首先向所有Server提议自己要成为leader,当其它Server收到提议以后,解决epoch和 zxid的冲突,并接受对方的提议,然后向对方发送接受提议完成的消息,重复这个流程,最后一定能选举出Leader。

选举的具体流程图如下所示:

Java大型互联网架构-分布式系统服务框架Zookeeper介绍与原理实现

zk fast paxos选举

同步流程

选完leader以后,zk就进入状态同步过程。

leader等待server连接;

Follower连接leader,将最大的zxid发送给leader;

Leader根据follower的zxid确定同步点;

完成同步后通知follower 已经成为uptodate状态;

Follower收到uptodate消息后,又可以重新接受client的请求进行服务了。

同步的具体流程图如下所示:

Java大型互联网架构-分布式系统服务框架Zookeeper介绍与原理实现

zk同步流程

工作流程

Leader工作流程

恢复数据;

维持与Learner的心跳,接收Learner请求并判断Learner的请求消息类型;

Learner的消息类型主要有PING消息、REQUEST消息、ACK消息、REVALIDATE消息,根据不同的消息类型,进行不同的处理。

PING 消息是指Learner的心跳信息;

REQUEST消息是Follower发送的提议信息,包括写请求及同步请求;

ACK消息是Follower的对提议 的回复,超过半数的Follower通过,则commit该提议;

REVALIDATE消息是用来延长SESSION有效时间。

Leader的工作流程简图具体如下所示:

Java大型互联网架构-分布式系统服务框架Zookeeper介绍与原理实现

Leader工作流程

Follower工作流程

Follower主要有四个功能:

Leader发送请求(PING消息、REQUEST消息、ACK消息、REVALIDATE消息);

接收Leader消息并进行处理;

接收Client的请求,如果为写请求,发送给Leader进行投票;

返回Client结果。

Follower的消息循环处理如下几种来自Leader的消息:

PING消息: 心跳消息;

PROPOSAL消息:Leader发起的提案,要求Follower投票;

COMMIT消息:服务器端最新一次提案的信息;

UPTODATE消息:表明同步完成;

REVALIDATE消息:根据Leader的REVALIDATE结果,关闭待revalidate的session还是允许其接受消息;

SYNC消息:返回SYNC结果到客户端,这个消息最初由客户端发起,用来强制得到最新的更新。

Follower的工作流程简图具体如下所示:

Java大型互联网架构-分布式系统服务框架Zookeeper介绍与原理实现

Follower的工作流程

总结

上就是我对Java大型互联网架构-分布式系统服务框架Zookeeper介绍与原理实现 问题及其优化总结,分享给大家,觉得收获的话可以点个关注收藏转发一波喔,谢谢大佬们支持!

最后,每一位读到这里的网友,感谢你们能耐心地看完。希望在成为一名更优秀的Java程序员的道路上,我们可以一起学习、一起进步!都能赢取白富美,走向架构师的人生巅峰!

https://mp.weixin.qq.com/s/vkvYJnKfQyuUeD_BDQy_1g

获取更多学习资料,可以加群:473984645或扫描下方二维码

Java大型互联网架构-分布式系统服务框架Zookeeper介绍与原理实现

相关推荐