转自:http://blog.sina.com.cn/s/blog_3fe961ae01012jod.html
1.发起一轮投票选举,推举自己作为leader,通知所有的服务器。
通知中包含以下数据:1)所选举leader的id(就是配置文件中写好的每个服务器的id),在初始阶段,每台服务器的这个值都是自己服务器的id,也就是推荐自己为leader。
2)zxid(越大表示数据最新)
3)logicalclock(electionEpoch)
4)本机状态(LOOKING、LEADING、FOLLOWING、OBSERVING)
2.只要当前服务器状态为LOOKING且不为stop,进入循环,不断地读取其它Server发来的通知、进行比较、更新自己的投票、发送自己的投票、统计投票结果,直到leader选出或出错退出。具体作法:
从队列中取出一个notification(内含对方的投票信息),判断对方服务器是否是投票参与者(server.type == LearnerType.PARTICIPANT)。如果不是,则继续等待下一个notification。是,则根据消息中对方的状态进行相应的处理。
1)LOOKING状态:
a.消息epoch>自己的logicalclock,表示对方已经开始新一轮选举了,更新logicalclock为epoch,清空接收到的所有服务器状态recvset。对比消息的zxid和本地的lastzxid,选取最大的作为leader,如果相同,则选取serverid最大的作为leader,然后sendNotifications()通知所有服务器我的选择。
b.消息的epoch<自己的logicalclock,表示这条消息是前面一轮的消息,于是回发一条消息告诉对方当前的机器的logicalclock和推举的leader和zxid。
c.消息epoch=自己的logicalclock,表示是同一轮选举,对比消息的zxid和本地的lastzxid,选取最大的作为leader,如果相同,则选取serverid最大的作为leader.如果返回的消息是最后选择,则sendNotifications()通知所有服务器我的选择,否则不理睬这条消息,不发送任何回应。
d.将收到的投票放入自己的投票箱中。e.调用计票器的containsQuorum函数,判断所推荐的leader是否得到集群多数人的同意(根据计票器的实现不同,可以是单纯看数量是否超过n/2,也可以是按权重来判断,我们这里假设单纯看数量),如果得到多数人同意,那么还需等待一段时间,看是否有比当前更优的提议,如果没有,则认为投票结束。根据投票结果修改自己的状态。以上任何一条不满足,则继续循环。
2)OBSERVING状态:不做任何事。
3)FOLLOWING或LEADING状态:a.如果逻辑时钟相同,将该数据保存到投票箱,根据当前投票箱的投票判断对方推荐的leader是否得到多数人的同意,如果是则设置状态退出选举过程。
b.消息的epoch<>自己的logicalclock,那么投票将加入到outofelection中,如果有1/2服务器以上的投票选择这条消息推荐的leader,那么更改自身的状态并返回。
3、当前服务器状态不为LOOKING,从一个正在looking的服务器接收到一条消息:
获得当前的leader信息,直接通知对方已经选择的leader.
4、当前服务器状态不为LOOKING,从一个状态不为looking的服务器接收到一条消息:
什么也不做。