ZooKeeper 소스 해석: Leader 선거

6728 단어 zookeeper
Leader 선거는 마스터 선거라고도 부른다.그럼 왜 리더 선거가 필요한가요?ZooKeeper는 모든 서비스(서버로 이해할 수 있음)에서 Leader를 선택하고 이 Leader가 그룹을 관리하는 것을 책임져야 합니다.이때 그룹의 다른 서버는 이 Leader의 팔로워가 됩니다.그리고 리더가 고장났을 때 ZooKeeper는 Follower에서 다음 리더를 신속하게 선출할 수 있어야 한다.이것이 바로 ZooKeeper의 Leader 메커니즘입니다. 다음은 ZooKeeper를 사용하여 Leader 선거(Leader Election)를 실현하는 방법을 간단히 소개합니다.
이 작업의 핵심 사상은 먼저 EPHEMERAL의 노드를 만드는 것이다. 예를 들어 "/election"이다.그리고 모든 ZooKeeper 서버는 이 디렉터리에 SEQUENCE | EPHEMERAL 형식의 노드를 만듭니다. 예를 들어 "/election/nu"입니다.SEQUENCE 로고에서 ZooKeeper는 자동으로 모든 ZooKeeper 서비스에 앞에서 지정한 번호보다 큰 번호를 할당합니다.노드 ZooKeeper 서버에 최소 번호가 있는 서버가 Leader가 됩니다.
실제 작업에서 Leader 서버가 고장났을 때 시스템은 다음 ZooKeeper 서버를 Leader로 신속하게 선택할 수 있음을 보증해야 한다.간단한 방안은 모든 Follower가 리더에 대응하는 노드를 감시하도록 하는 것이다.Leader에 장애가 발생하면 Leader에 대응하는 임시 노드가 자동으로 삭제됩니다. 이 동작은 Leader를 감시하는 모든 서버의watch를 터치합니다.이렇게 하면 이 서버들은 Leader 고장 소식을 받고 다음 Leader 선거 조작을 진행할 것이다.그러나 이런 조작은'종중효과'의 발생을 초래할 것이다. 특히 집단에 서버가 많고 광대역 지연이 비교적 클 때 더욱 뚜렷해진다.ZooKeeper에서 대중 효과의 발생을 피하기 위해 이것은 이렇게 이루어진다. 모든 Follower는 Follower 집단에서 자신의 노드 번호보다 작은 노드 중 x번호가 가장 큰 노드에watch를 설정한다.Followers가 설정한 watch가 촉발되었을 때만 Leader 선거 조작을 깨울 수 있습니다. 일반적인 상황에서 이것은 집단의 다음 Leader가 될 것입니다.분명히 이 Leader 선거의 조작 속도는 매우 빠르다.매번 Leader 선거는 거의 하나의 Follower 작업만 다루기 때문이다.다음은 원본 코드가 어떻게 실현되었는지 봅시다org.apache.zookeeper.recipes.leader.LeaderElectionSupport 구체적인 실현 논리는 이 종류에 있다.우선 start 방법이 하나 있습니다. 이 방법에서 먼저 호출된 것을 볼 수 있습니다makeOffer(); determineElectionStatus();
 /**
     * 
     */
    public synchronized void start() {
        state = State.START;
        //  
        dispatchEvent(EventType.START);

        LOG.info("Starting leader election support");

        if (zooKeeper == null) {
            throw new IllegalStateException(
                "No instance of zookeeper provided. Hint: use setZooKeeper()");
        }

        if (hostName == null) {
            throw new IllegalStateException(
                "No hostname provided. Hint: use setHostName()");
        }

        try {
            makeOffer();
            determineElectionStatus();
        } catch (KeeperException | InterruptedException e) {
            becomeFailed(e);
        }
    }

makeOffer() 방법을 살펴보겠습니다. 이 방법은 주로 임시 노드를 만드는 것입니다.

    /**
     *    root  
     * @throws KeeperException
     * @throws InterruptedException
     */
    private void makeOffer() throws KeeperException, InterruptedException {
        state = State.OFFER;
        dispatchEvent(EventType.OFFER_START);

        LeaderOffer newLeaderOffer = new LeaderOffer();
        byte[] hostnameBytes;
        synchronized (this) {
            newLeaderOffer.setHostName(hostName);
            hostnameBytes = hostName.getBytes();
            newLeaderOffer.setNodePath(zooKeeper.create(rootNodeName + "/" + "n_",
                                                        hostnameBytes, ZooDefs.Ids.OPEN_ACL_UNSAFE,
                                                        //  
                                                        CreateMode.EPHEMERAL_SEQUENTIAL));
            leaderOffer = newLeaderOffer;
        }
        LOG.debug("Created leader offer {}", leaderOffer);

        dispatchEvent(EventType.OFFER_COMPLETE);
    }


그리고 바로determineElectionStatus() 이 방법은 파일 목록 아래의 모든 파일을 가져옵니다. 가장 작은 것은leader로 설정된 다른 노드에 이전의 감청을 추가합니다.

    /**
     * 
     *    leader
     * @throws KeeperException
     * @throws InterruptedException
     */
    private void determineElectionStatus() throws KeeperException, InterruptedException {

        state = State.DETERMINE;
        dispatchEvent(EventType.DETERMINE_START);

        LeaderOffer currentLeaderOffer = getLeaderOffer();

        String[] components = currentLeaderOffer.getNodePath().split("/");

        currentLeaderOffer.setId(Integer.valueOf(components[components.length - 1].substring("n_".length())));

        List leaderOffers = toLeaderOffers(zooKeeper.getChildren(rootNodeName, false));

        /*
         * For each leader offer, find out where we fit in. If we're first, we
         * become the leader. If we're not elected the leader, attempt to stat the
         * offer just less than us. If they exist, watch for their failure, but if
         * they don't, become the leader.
         */
        for (int i = 0; i < leaderOffers.size(); i++) {
            LeaderOffer leaderOffer = leaderOffers.get(i);

            if (leaderOffer.getId().equals(currentLeaderOffer.getId())) {
                LOG.debug("There are {} leader offers. I am {} in line.", leaderOffers.size(), i);

                dispatchEvent(EventType.DETERMINE_COMPLETE);

                if (i == 0) {
                    //  leader
                    becomeLeader();
                } else {
                    //  leader
                    becomeReady(leaderOffers.get(i - 1));
                }

                /* Once we've figured out where we are, we're done. */
                break;
            }
        }
    }

리더가 되지 않은 노드가 이전 노드를 감청하지 않으면 이전 노드가 고장나면 위의 방법을 다시 실행합니다

    private void becomeReady(LeaderOffer neighborLeaderOffer)
        throws KeeperException, InterruptedException {

        LOG.info(
            "{} not elected leader. Watching node: {}",
            getLeaderOffer().getNodePath(),
            neighborLeaderOffer.getNodePath());

        /*
         * Make sure to pass an explicit Watcher because we could be sharing this
         * zooKeeper instance with someone else.
         */
        /**
         *
         *  watch,     determineElectionStatus
         */
        Stat stat = zooKeeper.exists(neighborLeaderOffer.getNodePath(), this);

        if (stat != null) {
            dispatchEvent(EventType.READY_START);
            LOG.debug(
                "We're behind {} in line and they're alive. Keeping an eye on them.",
                neighborLeaderOffer.getNodePath());
            state = State.READY;
            dispatchEvent(EventType.READY_COMPLETE);
        } else {
            /*
             * If the stat fails, the node has gone missing between the call to
             * getChildren() and exists(). We need to try and become the leader.
             */
            LOG.info(
                "We were behind {} but it looks like they died. Back to determination.",
                neighborLeaderOffer.getNodePath());
            determineElectionStatus();
        }

    }

더 많은 주석은 여기 보시면 돼요.https://github.com/haha174/zookeeper/commit/1174717483578074654bbc6a8a1e4744b9c255a9

좋은 웹페이지 즐겨찾기