Zookeeper源码分析(五)-Zookeeper选举实例流程

来源:互联网 发布:windows测试端口通不通 编辑:程序博客网 时间:2024/06/05 11:36

之前源码已经讲述完了,现在准备根据例子记录一下整个流程,加入我们在zoo.cfg里配置了四台服务器,分别是

server.1=zoo1:2888:3888:participant  server.2=zoo2:2888:3888:observer  server.3=zoo3:2888:3888:participantserver.4=zoo4:2888:3888:participant

首先我们启动zoo1,则他就会做如下事情:

1.投自己一票:Vote(1,zoo1.zxid,zoo1.epoch);2.设置属性:quorumpeer.myQuorumAddr=zoo1:2888;3.通过绑定electionAddr=zoo1:3888来开启与客户端通信的连接;4.开启WorkerSender和WorkerReceiver用于消息的发送和接收;5.开启zoo1的quorumPeer的线程;6.一开始quorumPeer.serverState都为LOOKING,所以运行选举策略的lookForLeader()方法;7.更新提议,即设置proposedLeader=1,proposedZxid=zoo1.zxid,proposedEpoch=zoo1.epoch8.通过sendNotifications()方法(遍历三台participant服务器,即zoo1,zoo3,zoo4.封装三个ToSend对象,分别为toSend1(ToSend.mType.notification,1,zoo1.zxid,logicalclock,LOOKING,1,zoo1.epoch)toSend3(ToSend.mType.notification,1,zoo1.zxid,logicalclock,LOOKING,3,zoo1.epoch)toSend4(ToSend.mType.notification,1,zoo1.zxid,logicalclock,LOOKING,4,zoo1.epoch)放入FastLeaderElection.sendqueue队列中;其实这里的功能就是投票告诉zoo1,zoo3,zoo4,我(zoo1)投票选举zoo1为Leader.9.WorkerSender线程会实时从FastLeaderElection.sendqueue中取ToSend对象转换为ByteBuffer对象,通过QuorumCnxManager的toSend方法发送,发送的原理是:9.1 toSend1是发给自己,则将ByteBuffer转换为Message对象放入QuorumCnxManager.recvQueue队列中;9.2 toSend3是不是发给自己的,则插入QuorumCnxManager.queueSendMap(即无则插入,有则更新);并且去连接zoo3的选举地址:zoo3:3888,方法为connectOne(3)。因为现在zoo3服务器没启动,所以connectOne(3)方法失败;接着是toSend4,也插入QuorumCnxManager.queueSendMap(即对应sid无则插入,有则更新);并且去连接zoo4的选举地址:zoo4:3888,方法为connectOne(4),同理也失败。10.WorkerReceiver线程会实时从QuorumCnxManager.recvQueue里去Message对象,因为只启动了zoo1,所以recvQueue里只有一条Message,因为这个Message是participant,所以就封装成Notification对象,因为zoo1.quorumPeer是LOOKING,所以放入到FastLeaderElection.recvqueue中,并且因为该Message也是LOOKING,所以封装成ToSend对象放入FastLeaderElection.sendqueue中。11. 910两部是线程做的事情,紧接着8的是因为zoo1是LOOKING,所以实时从FastLeaderElection.recvqueue中取Notification对象,因为经过910两步recvqueue已经有对象了,所以就不用重新sendNotifications()和连接其他服务器选举端口了。接下来就是比较Notification对象和本地的信息,因为投票没有超过一半,所以结束本次分析recvqueue中Notification的对象。12. 因为只要zoo1是LOOKING,就会实时从recvqueue中取Notification取。不过因为11步已经取完了,所以取出来是个空的Notification对象,然后通过QuorumCnxManager的haveDelivered方法遍历QuorumCnxManager.queueSendMap来判断是否还有信息,因为9.2步已经说明里面还有的,所以继续sendNotifications();13. 然后就一直循环在8-12步,报无法连接zoo3,和zoo4的错误。

接下来我们去启动 zoo2服务器。注意zoo2是observer.

1.投自己一票:Vote(2,zoo2.zxid,zoo2.epoch);2.设置属性:quorumpeer.myQuorumAddr=zoo2:2888;3.通过绑定electionAddr=zoo2:3888来开启与客户端通信的连接;4.开启WorkerSender和WorkerReceiver用于消息的发送和接收;5.开启zoo2的quorumPeer的线程;6.一开始quorumPeer.serverState都为LOOKING,所以运行选举策略的lookForLeader()方法;7.更新提议,因为是observer,即设置proposedLeader=Long.MIN_VALUE,proposedZxid=zoo2.zxid,proposedEpoch=zoo2.epoch8.通过sendNotifications()方法(遍历三台participant服务器,即zoo1,zoo3,zoo4.封装三个ToSend对象,分别为toSend1(ToSend.mType.notification,Long.MIN_VALUE,zoo2.zxid,logicalclock,LOOKING,1,zoo2.epoch)toSend3(ToSend.mType.notification,Long.MIN_VALUE,zoo2.zxid,logicalclock,LOOKING,3,zoo2.epoch)toSend4(ToSend.mType.notification,Long.MIN_VALUE,zoo2.zxid,logicalclock,LOOKING,4,zoo2.epoch)放入FastLeaderElection.sendqueue队列中;其实这里的功能就是投票告诉zoo1,zoo3,zoo4,我(zoo2)投票选举zoo2为Leader.9.WorkerSender线程会实时从FastLeaderElection.sendqueue中取ToSend对象转换为ByteBuffer对象,通过QuorumCnxManager的toSend方法发送,发送的原理是:9.1 toSend1的sid和本机的不一样,则插入QuorumCnxManager.queueSendMap(即无则插入,有则更新);并且去连接zoo1的选举地址:zoo1:3888,方法为connectOne(1)。因为现在zoo1服务器已经启动,所以connectOne(1)方法成功,在connectOne(1)中的initiateConnection(socket,sid)中,通过开启SendWorker和RecvWorker进行zoo2和zoo1的信息共享(往senderWorkerMap加入zoo1.sid和相应socket;SendWorker负责发送zoo1.sid最近一条消息的ByteBuffer,RecvWorker负责封装ByteBuffer放入QuorumCnxManager.recvQueue中,然后删除QuorumCnxManager.queueSendMap中相应的消息);接着是toSend3,也插入QuorumCnxManager.queueSendMap(即对应sid无则插入,有则更新);并且去连接zoo3的选举地址:zoo3:3888,方法为connectOne(3),因为zoo3为开启,所以连接失败,同理zoo4也失败。10.WorkerReceiver线程会实时从QuorumCnxManager.recvQueue里去Message对象,因为recvQueue里存了一条zoo1最近发送的Message,因为这个Message是participant,所以就封装成Notification对象,因为zoo2.quorumPeer是LOOKING,所以放入到FastLeaderElection.recvqueue中,并且因为该Message也是LOOKING,所以封装成ToSend对象放入FastLeaderElection.sendqueue中。11. 910两部是线程做的事情,紧接着8的是因为zoo2是LOOKING,所以实时从FastLeaderElection.recvqueue中取Notification对象,因为经过910两步recvqueue已经有了最近一条消息对象了,所以就不用重新sendNotifications()和连接其他服务器选举端口了。接下来就是比较Notification对象和本地的信息,因为Notification对象比本地的小,所以更新为本地的提议,sendNotifications()出去,因为投票没有超过一半,所以结束本次分析recvqueue中Notification的对象。12. 因为只要zoo2是LOOKING,就会实时从recvqueue中取Notification取。因为第10步有sendNotifications(),所以recvqueue中还有Notification对象,继续第10步后发现Notification对象和本地的一样了,就不继续sendNotifications()。13. 之后又是取Notification对象,不过因为11步已经取完了,所以取出来是个空的Notification对象,然后通过QuorumCnxManager的haveDelivered方法遍历QuorumCnxManager.queueSendMap来判断是否还有信息,因为9.1步已经删除了,所以没有了,所以调用connectAll()方法,开启连接zoo1,zoo3,zoo4;14. 然后就一直循环12步,连接zoo1,报无法连接zoo3,和zoo4的错误。
0 0
原创粉丝点击