www

导航

zookeeper选主(四)-Leader.lead()

    /**
     * Leader#lead()
     * <p>
     * 当前节点是Leader
     */
    void lead() throws IOException, InterruptedException {
        try {
            zk.loadData();
            // leaderStateSummary-如果有更新的节点突然启动,会导致LearnerHandler中waitForEpochAck抛异常
            leaderStateSummary = new StateSummary(self.getCurrentEpoch(), zk.getLastProcessedZxid());
            cnxAcceptor = new LearnerCnxAcceptor();
            // ip:port1:port2  port1端口为数据通信端口,port2为选举通信端口
            cnxAcceptor.start();
            // 会在这里阻塞,直到有过半的节点参与,才会唤醒(可能因为超时导致Leader宣告统治失败)
            long epoch = getEpochToPropose(self.getId(), self.getAcceptedEpoch());

            zk.setZxid(ZxidUtils.makeZxid(epoch, 0));

            synchronized (this) {
                lastProposed = zk.getZxid();
            }
            newLeaderProposal.packet = new QuorumPacket(NEWLEADER, zk.getZxid(), null, null);

            // 在这里阻塞,可能因为超时导致新Leader宣告统治失败
            waitForEpochAck(self.getId(), leaderStateSummary);
            self.setCurrentEpoch(epoch);

            try {
                // 统一zxid,也可能宣告统治失败
                waitForNewLeaderAck(self.getId(), zk.getZxid());
            } catch (InterruptedException e) {
                shutdown("Waiting for a quorum of followers, only synced with sids: [ "
                        + getSidSetString(newLeaderProposal.ackSet) + " ]");
                HashSet<Long> followerSet = new HashSet<>();
                for (LearnerHandler f : learners) {
                    followerSet.add(f.getSid());
                }
                // 重点,时间设置过短
                if (self.getQuorumVerifier().containsQuorum(followerSet)) {
                    LOG.warn("Enough followers present. "
                            + "Perhaps the initTicks need to be increased.");
                }
                Thread.sleep(self.tickTime);
                self.tick.incrementAndGet();
                // 正常退出,重新选主
                return;
            }
            // 选主结束
            // 启动zk服务,对外提供服务
            startZkServer();

            String initialZxid = System.getProperty("zookeeper.testingonly.initialZxid");
            if (initialZxid != null) {
                long zxid = Long.parseLong(initialZxid);
                zk.setZxid((zk.getZxid() & 0xffffffff00000000L) | zxid);
            }

            if (!System.getProperty("zookeeper.leaderServes", "yes").equals("no")) {
                self.cnxnFactory.setZooKeeperServer(zk);
            }

            boolean tickSkip = true;

            // 心跳检测
            while (true) {
                Thread.sleep(self.tickTime / 2);
                if (!tickSkip) {
                    self.tick.incrementAndGet();
                }
                HashSet<Long> syncedSet = new HashSet<>();

                syncedSet.add(self.getId());

                for (LearnerHandler learnerHandler : getLearners()) {
                    if (learnerHandler.synced() && learnerHandler.getLearnerType() == LearnerType.PARTICIPANT) {
                        syncedSet.add(learnerHandler.getSid());
                    }
                    learnerHandler.ping();
                }
                if (!this.isRunning()) {
                    shutdown("Unexpected internal error");
                    return;
                }
                if (!tickSkip && !self.getQuorumVerifier().containsQuorum(syncedSet)) {
                    shutdown("Not sufficient followers synced, only synced with sids: [ "
                            + getSidSetString(syncedSet) + " ]");
                    return;
                }
                tickSkip = !tickSkip;
            }
        } finally {
            zk.unregisterJMX(this);
        }
    }
        /**
         * LearnerCnxAcceptor.start()
         */
        @Override
        public void run() {
            try {
                while (!stop) {
                    try {
                        Socket connSocket = ss.accept();

                        connSocket.setSoTimeout(self.tickTime * self.initLimit);
                        connSocket.setTcpNoDelay(nodelay);

                        BufferedInputStream is = new BufferedInputStream(
                                connSocket.getInputStream());
                        LearnerHandler learnerHandler = new LearnerHandler(connSocket, is, Leader.this);
                        learnerHandler.start();
                    } catch (SocketException e) {
                        if (stop) {
                            stop = true;
                        } else {
                            throw e;
                        }
                    } catch (SaslException e) {
                        LOG.error("Exception while connecting to quorum learner", e);
                    }
                }
            } catch (Exception e) {
                LOG.warn("Exception while accepting follower", e);
            }
        }

        void halt() {
            stop = true;
        }
    }
    /**
     * Leader#getEpochToPropose()和LearnerHandler#getEpochToPropose()
     * <p>
     * 和LearnerHandler(与其他节点的一对一连接)
     */
    long getEpochToPropose(long sid, long lastAcceptedEpoch) throws InterruptedException, IOException {
        synchronized (connectingFollowers) {
            // 重点,如果已经新的统治轮次计算完成,直接返回
            if (!waitingForNewEpoch) {
                return epoch;
            }
            if (lastAcceptedEpoch >= epoch) {
                epoch = lastAcceptedEpoch + 1;
            }
            if (isParticipant(sid)) {
                connectingFollowers.add(sid);
            }
            QuorumVerifier verifier = self.getQuorumVerifier();
            // 过半原则,计算出新的统治轮次
            if (connectingFollowers.contains(self.getId()) && verifier.containsQuorum(connectingFollowers)) {
                waitingForNewEpoch = false;
                self.setAcceptedEpoch(epoch);
                connectingFollowers.notifyAll();
            } else {
                long start = Time.currentElapsedTime();
                long cur = start;
                long end = start + self.getInitLimit() * self.getTickTime();
                // 阻塞,超时就退出
                while (waitingForNewEpoch && cur < end) {
                    connectingFollowers.wait(end - cur);
                    cur = Time.currentElapsedTime();
                }
                if (waitingForNewEpoch) {
                    throw new InterruptedException("Timeout while waiting for epoch from quorum");
                }
            }
            return epoch;
        }
    }
    void waitForEpochAck(long id, StateSummary ss) throws IOException, InterruptedException {
        synchronized (electingFollowers) {
            if (electionFinished) {
                return;
            }
            if (ss.getCurrentEpoch() != -1) {
                if (ss.isMoreRecentThan(leaderStateSummary)) {
                    throw new IOException("Follower is ahead of the leader, leader summary: "
                            + leaderStateSummary.getCurrentEpoch()
                            + " (current epoch), "
                            + leaderStateSummary.getLastZxid()
                            + " (last zxid)");
                }
                if (isParticipant(id)) {
                    electingFollowers.add(id);
                }
            }
            QuorumVerifier verifier = self.getQuorumVerifier();
            if (electingFollowers.contains(self.getId()) && verifier.containsQuorum(electingFollowers)) {
                electionFinished = true;
                electingFollowers.notifyAll();
            } else {
                long start = Time.currentElapsedTime();
                long cur = start;
                long end = start + self.getInitLimit() * self.getTickTime();
                while (!electionFinished && cur < end) {
                    electingFollowers.wait(end - cur);
                    cur = Time.currentElapsedTime();
                }
                if (!electionFinished) {
                    throw new InterruptedException("Timeout while waiting for epoch to be acked by quorum");
                }
            }
        }
    }

posted on 2020-10-01 12:44  www_practice  阅读(326)  评论(0编辑  收藏  举报