Zookeeper源码分析(五)-Zookeeper选举实例流程
2015-10-19 10:53
239 查看
之前源码已经讲述完了,现在准备根据例子记录一下整个流程,加入我们在zoo.cfg里配置了四台服务器,分别是
首先我们启动zoo1,则他就会做如下事情:
接下来我们去启动 zoo2服务器。注意zoo2是observer.
server.1=zoo1:2888:3888:participant server.2=zoo2:2888:3888:observer server.3=zoo3:2888:3888:participant server.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.epoch 8.通过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. 9和10两部是线程做的事情,紧接着8的是因为zoo1是LOOKING,所以实时从FastLeaderElection.recvqueue中取Notification对象,因为经过9和10两步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.epoch 8.通过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. 9和10两部是线程做的事情,紧接着8的是因为zoo2是LOOKING,所以实时从FastLeaderElection.recvqueue中取Notification对象,因为经过9和10两步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的错误。
相关文章推荐
- js MD5加密 和 base64编码实现!
- Java解析XML汇总(DOM/SAX/JDOM/DOM4j/XPath)
- iOS5中UIViewController的新方法
- 摩尔纹的原理与产生条件
- svn小知识
- HTTP必知必会
- 3个IO口8个按键
- 代码:显示当前系统时间
- Android 中关于 TextView中链接的拦截
- ThreadLocal,静态变量,实例变量,局部变量的线程安全,回复:ByteBuffer 到底怎么用?网络编程中一点总结!
- Java并发编程:volatile关键字解析
- sql server 行转列(转载)
- 黑马程序员--Java学习日记之基础知识(思维导图&基础概念)
- 基于环信和百度地图的一个项目总结
- android.support.v4.widget.SwipeRefreshLayout布局Xml 文件
- 无线路由接入
- 字符串笔试面试题
- 用Maonry如何实现UIScrollView
- android:windowSoftInputMode属性详解
- 欢迎使用CSDN-markdown编辑器