1. 参与选举的角色分析
1.1 投票人
投票人, 在zookeeper里节点类型为LearnerType. PARTICIPANT的都可以投票
投票人(QuorumPeer)包含的主要信息有:
- 基本属性
private long myid;//节点的sid
private QuorumPeer.ServerState state;//节点的状态
private volatile Vote currentVote;//当前状态下胜出的选票
private final long zxid;//当前事务id
private final long electionEpoch;//当前已选出选票的周期
- 选举过程中的属性
AtomicLong logicalclock = new AtomicLong();//当前节点视觉的选举周期
long proposedLeader;//当前节点推选人的sid
long proposedZxid; //当前节点推选人的事务id
long proposedEpoch; //当前节点推选人的选举周期
-
投票人可以发起选举
当集群中找不到leader时, 就会发起选举. 选举调用及过程参考QuorumPeer.run方法和FastLeaderElection.lookForLeader方法 -
选票PK
当前节点收到其他节点的选票时, 会进行选票PK, 若PK失败会更新推选人并广播新选票
选票PK原则:
1.其他节点选票周期epoch>当前推选人周期,清空recvset投票箱,更新选票
2.其他节点选票zxid>当前推选人zxid, 更新选票
3.其他节点选票的sid>当前节点推选人sid, 更新选票
1.2 候选人
在zookeeper里的投票人, 都可以参选作为候选人
每个投票人的视觉都有一个推选人, 即候选人. 包含以下信息:
long proposedLeader;//当前节点推选人的sid
long proposedZxid; //当前节点推选人的事务id
long proposedEpoch; //当前节点推选人的选举周期
1.3 选票
选票, 即被某个投票人节点推选为leader的某节点信息, 包含以下信息:
private final int version;//版本
private final long id;//选票的推选人sid
private final long zxid;//选票的推选人zxid
private final long electionEpoch;//选票的选举周期
private final long peerEpoch;//该选票对应投票人的当前选举周期
private final ServerState state;//该选票对应投票人的节点状态
1.4 投票箱
HashMap<Long, Vote> recvset = new HashMap();
HashMap<Long, Vote> outofelection = new HashMap();
key为该选票对应投票人的sid
value值为对应的选票
recvset投票箱:存放当前选举周期的选票,投票人可以状态为(LOOKING/LEADING/FOLLOWING)
outofelection投票箱:存放从其他节点获取的当选者信息
- 统计选票
- 当集群中大于一半的节点的选票为同一个节点, 则该节点当选为leader
- 优先使用recvset投票箱统计选票,再使用outofelection统计
recvset投票箱:适用于同周期选举活跃的节点用来统计选票
outofelection投票箱:适用于失联后的节点同步集群当前当选者信息
1.5 当选者
节点当选后设置节点状态为LEADING状态, 并广播该状态.
当节点大于一半的节点确定自己的状态后, 开始恢复为服务模式, 接收客户端的请求
2. 选举流程
FastLeaderElection.lookForLeader选举实现
选举核心流程:
2.1 两个投票箱
- recvset投票箱
HashMap<Long, Vote> recvset = new HashMap();
当前选举周期的投票箱A. 接收投票人节点为LOOKING/FOLLOWING/LEADING状态且选票周期等于当前周期的选票(大于时会清空原选票) - outofelection投票箱
HashMap<Long, Vote> outofelection = new HashMap();
投票箱B. 接收状态为FOLLOWING/LEADING的投票人节点(任何周期)的选票 - 选举结束的条件
1.超过一半的节点的选票为同一个节点且200ms内没有新的选票
2.先判断投票箱A, 再判断投票箱B
2.2 选票PK
当前节点收到其他节点的选票时, 会和当前推选人进行PK, 若PK失败会更新推选人并广播新选票
- 选票PK原则:
1.其他节点选票周期epoch>当前推选人周期,清空recvset投票箱,更新选票
2.其他节点选票zxid>当前推选人zxid, 更新选票
3.其他节点选票的sid>当前节点推选人sid, 更新选票
3. 选票流转分析
3.1 传播过程中字节格式的选票Buffer
长度共44字节, 由于节点间的连接双方有对方的sid, 因此可以获取到投票人sid
3.2 选举过程中的选票Vote
选票信息对象
private final int version;
private final long id;//选票对应节点的sid
private final long zxid;//选票对应节点的事务id
private final long electionEpoch;//选票对应节点的选举周期
private final long peerEpoch;//当前节点的选举周期
private final ServerState state;//当前节点的状态
3.3 选票流转过程
参考以下流程: