2.一样的选举流程
leader选举的大体流程都是一样的,这里将不再赘述,当完成选举以后,每个服务端实例按照自身的角色,将自身的状态修改为对应的角色状态,这个时候选举完成,zookeeper集群恢复对外提供服务。
zookeeper的选举算法
zookeeper的选举的大概流程我们知道了,但是我们都知道,选举的过程是基于算法的,zookeeper的选举算法有哪些呢?在zookeeper中,提供了三种leader选举的算法,分别是leaderelection、udp版本的fastleaderelection以及tcp版本的fastleaderelection三种选举算法。而选举算法,则是可以在zoo.cfg配置文件中的electionalg属性来指定,这三种选举算法分别对应值为0-3,其中0为leaderelection算法,使用的是udp协议实现,1代表udp版本的fastleaderelection算法,这种算法是非授权模式,2代表的也是udp版本的fastleaderelection算法,不过这种使用的是授权模式,3代表是tcp协议实现的fastleaderelection算法。
不过需要注意的是,从zookeeper3.4.x版本开始,zookeeper官方已经废弃了udp协议实现的0-2这三种leader选举算法,仅仅保留了3这一种tcp协议实现的fastleaderelection算法,这也是为什么上面我们介绍选举的大致流程中不针对每一种选举算法进行分析的原因。
leader选举的细节
学习了选举的大概流程以后,我们发现整体流程和算法的设计不难,但是具体如何处理常见的问题的?这个时候我们需要深入细节来学习,首先zookeeper为了处理不同情况,设计了多个服务端的状态,这个状态的定义在org .apache . zookeeper . server.quorum .quorumpeer. serverstate 类中,分别如下:
①looking:寻找leader服务的状态,处于当前状态后,将会进行leader选举流程
②following:代表当前服务端处于跟随者状态,表明是follower服务
③leading:代表当前服务端处于领导者状态,表明是leader服务
④observing:观察者状态,表明是observer服务
前面我们也提到过,每次发出选票后,选票中包含了基本的元素,即zxid和myid,而这个选票的定义在 apache.zookeeper.server.quorum.vote类,代码如下:
1. `finalprivateint version;` 2. `finalprivatelong id;` 3. `finalprivatelong zxid;` 4. `finalprivatelong electionepoch;` 5. `finalprivatelong peerepoch;`
我们把常见的几个属性进行说明,如下:
属性 | 说明 |
---|---|
id | 被选举的sid |
zxid | 当前leader的事物id |
electionepoch | 逻辑时钟,解析出来的,当前处于第几轮选举投票,每次进入新一轮投票后,都会加1 |
peerepoch | 当前被选举的leader的epoch |
state | 当前服务所处于的状态 |
学习了这些后,我们来看看选举的通信,前面我们有聊过cilentcnxn是zookeeper客户端中用于处理i/o网络通信的管理器,而对应的zookeeper的server中也有一个类–quorumcnxmanager类来接受和处理leader选举中的通信,而整个过程可以划分几个部分,大致如下:
消息队列处理消息
在quorumcnxmanager类中维护了很多队列,用于保存接受到的、等待发送的消息,还定义了消息发送器等,除了接受队列以外,其他的队列都是按照sid分组的集合。其中常见的队列和属性定义如下:
-
recvqueue:消息接受队列,用于存放接受来的所有的消息
-
queuesendmap:消息待发送队列,用于保存等待发送的消息集合,定义为一个map,按照sid分组设置为key,并且每一个sid对应的都维护了一个队列,保证收发消息互不影响
-
senderworkmap:发送器集合,每一个senderwork发送器都对应一个远程连接的zookeeper,负责发送消息,在senderworkmap内部,也是按照sid分组进行维护的。
-
lastemessagesent:最近发送的消息,在这个集合中,会为每一个sid维护一个最新发送的消息
建立连接
为了能彼此之间通信,zookeeper集群中的实例需要两两建立连接,quorumcnxmanager类在启动的时候会创建一个serversokect来监听leader选举的通信端口,在接受到请求的时候,会调用receiveconnection函数来处理,但是为了避免重复的创建tcp连接,zookeeper建立了一个规则,只允许sid大的机器往sid小的机器建立连接,当连接连理后,根据远程服务实例的sid创建对应的senderworker和对应的消息接收器recvworker
消息接受和发送
当消息接收器不停的收到消息后,会将其保存在recvqueue队列中,消息发送比较简单,由于每一个sid都有一个维护的独立的sendworker,只需要不停的从queuesendmap获取要发送的数据进行发送即可,发送完毕后,会将刚刚发送的消息存入lastemessagesent中,但是需要注意的是,当发现代发送消息的队列是空的时候,就会从lastemessagesent中获取刚刚发送的消息,然后再次作为消息发送出去,这么设计的原因是为了防止接受方没有收到消息,或者是收到消息后挂了,导致消息没处理完,因为zookeeper自身对重复消息有处理机制,因此重复发送消息,可以保证能正确处理消息
fastleaderelection算法
zookeeper的选举网络io模块我们大致知道了,接下来我们来看看fastleaderelection选举算法的核心算法实现,流程图如下:
1.自增选举次数
在fastleaderelection的实现中,有一个logicalclock属性,用于标识当前选举的次数,zookeeper要求每次发起选举的时候必须是在同一次选举周期中,因此在每一次选举之前,都会触发logicalclock的自增,达到当前的选举周期
2.初始化选票
前面我们已经知道了选票类的定义在apache.zookeeper.server.quorum.vote,初始化阶段的时候,每台服务器都会推举自己为leader,因此都会先初始化一个以自己为主的选票
3.将初始化的选票发送
初始化完选票以后,会将自己的选票信息存入sendqueue队列中,然后用对应每一个sid的workersender负责发送出去
4.接受外部投票信息
小编13年上海交大毕业,曾经在小公司待过,也去过华为、oppo等大厂,18年进入阿里一直到现在。
深知大多数初中级java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面v无偿领取!(备注java)
记、源码讲义、实战项目、讲解视频**
如果你觉得这些内容对你有帮助,可以添加下面v无偿领取!(备注java)
[外链图片转存中…(img-ixvaq4uz-1710846531010)]
发表评论