本文共 2129 字,大约阅读时间需要 7 分钟。
zk节点状态:
服务可能处于的状态,从名字应该很好理解:
public enum ServerState { LOOKING, FOLLOWING, LEADING, OBSERVING;}
开始这个选举算法前,每个节点都会在zoo.cfg上指定的监听端口启动监听(server.1=127.0.0.1:20881:20882),这里的20882就是这里用于选举的端口。
每个集群中的节点都有一个状态 LOOKING, FOLLOWING, LEADING, OBSERVING。都属于这4种,每个节点启动的时候都是LOOKING状态,如果这个节点参与选举但最后不是leader,则状态是FOLLOWING,如果不参与选举则是OBSERVING,leader的状态是LEADING。选票的比较逻辑
选票的比较逻辑也很简单,依次比较几个关键字段
protected boolean totalOrderPredicate(long newId, long newZxid, long newEpoch, long curId, long curZxid, long curEpoch) { ... return ((newEpoch > curEpoch) || ((newEpoch == curEpoch) && ((newZxid > curZxid) || ((newZxid == curZxid) && (newId > curId))))); }
-
判断消息里的epoch是不是比当前的大,如果大则消息里id对应的server我就承认它是leader
-
如果epoch相等则判断zxid,如果消息里的zxid比我的大我就承认它是leader
-
如果前面两个都相等那就比较一下server id吧,如果比我的大我就承认它是leader。
关于前面两个东西暂时我们不去关心它,对于新启动的集群这两者都是相等的。
那这样看来server id的大小也是leader选举的一环啊(有的人生下来注定就不平凡,这都是命啊)。
最后我们来看看,很多文章所介绍的,如果超过一半的人说它是leader,那它就是leader的逻辑吧
private boolean termPredicate( HashMapvotes, Vote vote) { HashSet set = new HashSet (); //遍历已经收到的投票集合,将等于当前投票的集合取出放到set中 for (Map.Entry entry : votes.entrySet()) { if (self.getQuorumVerifier().getVotingMembers().containsKey(entry.getKey()) && vote.equals(entry.getValue())){ set.add(entry.getKey()); } } //统计set,也就是投某个id的票数是否超过一半 return self.getQuorumVerifier().containsQuorum(set); } public boolean containsQuorum(Set ackSet) { return (ackSet.size() > half); }
最后一关:如果选的是自己,则将自己的状态更新为LEADING,否则根据type,要么是FOLLOWING,要么是OBSERVING。
到这里选举就结束了。第一次启动选举:
第一次启动epoch和zxid这两个参数都是相等即为0, 这里介绍的是一个新集群启动时候的选举过程,启动的时候就是根据zoo.cfg里的配置,向各个节点广播投票,一般都是选投自己。然后收到投票后就会进行进行判断。如果某个节点收到的投票数超过一半,那么它就是leader了。一半以上follower挂掉:
一个集群有3台机器,挂了一台后的影响是什么?挂了两台呢?
挂了一台:挂了一台后就是收不到其中一台的投票,但是有两台可以参与投票,按照上面的逻辑,它们开始都投给自己,后来按照选举的原则,两个人都投票给其中一个,那么就有一个节点获得的票等于2,2 > (3/2)=1 的,超过了半数,这个时候是能选出leader的。
挂了两台: 挂了两台后,怎么弄也只能获得一张票, 1 不大于 (3/2)=1的,这样就无法选出一个leader了。
转载地址:https://blog.csdn.net/yangshengwei230612/article/details/117512963 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!