当前位置: 首页 > 分布式系统 > 正文

zookeeper源码分析:对leader选举过程分析的纠正

1 星2 星3 星4 星5 星 (2 次投票, 评分: 5.00, 总分: 5)
Loading ... Loading ...
baidu_share

之前分析的zookeeper leader选举算法有误,特此更正说明.

那里面最大的错误在于,leader选举其实不是在大多数节点通过就能选举上的,这一点与传统的paxos算法不同,因为如果这样的话,就会出现数据丢失的情况.比如某台服务器其实有最多的数据量,按照规则而言应该是leader,但是由于启动晚了,最后只能把leader让给其它的服务器.这里面存在明显的时序问题,也就是说leader服务器启动的早晚会影响整个过程.

实际上并不是这样,leader选举算法只有在收到所有参与服务器的回复才能结束.代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/*
                         * Only proceed if the vote comes from a replica in the
                         * voting view.
                         */
                        if(self.getVotingView().containsKey(n.sid)){
                            recvset.put(n.sid, new Vote(n.leader, n.zxid, n.epoch));
 
                            //If have received from all nodes, then terminate
                            if ((self.getVotingView().size() == recvset.size()) &&
                                    (self.getQuorumVerifier().getWeight(proposedLeader) != 0)){
                                self.setPeerState((proposedLeader == self.getId()) ?
                                        ServerState.LEADING: learningState());
                                leaveInstance();
                                return new Vote(proposedLeader, proposedZxid);
 
                            } else if (termPredicate(recvset,
                                    new Vote(proposedLeader, proposedZxid,
                                            logicalclock))) {
 
                                // Verify if there is any change in the proposed leader
                                while((n = recvqueue.poll(finalizeWait,
                                        TimeUnit.MILLISECONDS)) != null){
                                    if(totalOrderPredicate(n.leader, n.zxid,
                                            proposedLeader, proposedZxid)){
                                        recvqueue.put(n);
                                        break;
                                    }
                                }
 
                                /*
                                 * This predicate is true once we don't read any new
                                 * relevant message from the reception queue
                                 */
                                if (n == null) {
                                    self.setPeerState((proposedLeader == self.getId()) ?
                                            ServerState.LEADING: learningState());
                                    if(LOG.isDebugEnabled()){
                                        LOG.debug("About to leave FLE instance: Leader= "
                                            + proposedLeader + ", Zxid = " +
                                            proposedZxid + ", My id = " + self.getId()
                                            + ", My state = " + self.getPeerState());
                                    }
 
                                    leaveInstance();
                                    return new Vote(proposedLeader,
                                            proposedZxid);
                                }
                            }
                        }

简单的说,以上的代码分为两种情况进行处理:

1) 如果已经接收到所有服务器的封包(self.getVotingView().size() == recvset.size()),那么这台服务器选举的leader就定下来了.

2) 否则如果这个leader已经得到超过半数的服务器认同(函数termPredicate),那么当前线程将被阻塞等待一段时间(这个时间在finalizeWait定义)看看是不是还有其它服务器比当前leader更优的leader,如果经过一段时间还没有这个新的leader提出来,同样也是选举这个leader了,否则进行下一次选举.

对于过程2)我有一个疑问,同样是时序问题,如果那个真正的leader在这个时间点到来之前还没有启动,岂不是又成不了leader了?好吧,如果换了我的设计,应该全部走过程1),即在收到所有服务器的封包才做出决定,而如果在一段时间内没有收集起来所有的服务器封包,干脆退出好了.理由:干脆的死或者干脆的活比起半死不活总是好些的.

本文固定链接: http://www.chepoo.com/zookeeper-code-analysis-elect-leader-error.html | IT技术精华网

zookeeper源码分析:对leader选举过程分析的纠正:等您坐沙发呢!

发表评论