elasticsearch源码分析-02选举主节点

选举主节点

选举主节点入口方法在node的start方法中

 //node启动开始选举master节点
discovery.startInitialJoin();

@Override
public void startInitialJoin() {
   
    // start the join thread from a cluster state update. See {@link JoinThreadControl} for details.
    //从集群状态更新启动连接线程
    synchronized (stateMutex) {
   
        // do the join on a different thread, the caller of this method waits for 30s anyhow till it is discovered
        joinThreadControl.startNewThreadIfNotRunning();
    }
}

选举运行在线程池Generic中运行

public void startNewThreadIfNotRunning() {
   
    assert Thread.holdsLock(stateMutex);
    //线程已经运行直接退出
    if (joinThreadActive()) {
   
        return;
    }
    //提交任务
    threadPool.generic().execute(new Runnable() {
   
        @Override
        public void run() {
   
            Thread currentThread = Thread.currentThread();
            if (!currentJoinThread.compareAndSet(null, currentThread)) {
   
                return;
            }
            //不停执行加入集群服务
            while (running.get() && joinThreadActive(currentThread)) {
   
                try {
   
                    innerJoinCluster();
                    return;
                } catch (Exception e) {
   
                    logger.error("unexpected error while joining cluster, trying again", e);
                    assert ExceptionsHelper.reThrowIfNotNull(e);
                }
            }
        }
    });
}

首先判断是否已经有选举任务正在运行,如果有则直接退出,提交了一个任务到generic中运行,最终调用innerJoinCluster方法

  • 选举临时主节点
//选举临时master节点
masterNode = findMaster();

首先查询当前集群中活跃的主节点或者从主节点候选列表中选择新的主节点,如果选举成功则返回。我们分析一下该方法下的几个主要过程
发送ping请求到所有节点

//ping所有节点,并接受返回结果
List<ZenPing.PingResponse> fullPingResponses = pingAndWait(pingTimeout).toList();
if (fullPingResponses == null) {
   
    logger.trace("No full ping responses");
    return null;
}

protected void ping(final Consumer<PingCollection> resultsConsumer,
                        final TimeValue scheduleDuration,
                        final TimeValue requestDuration) {
   
    final List<TransportAddress> seedAddresses = new ArrayList<>();
    //所有节点地址
    seedAddresses.addAll(hostsProvider.getSeedAddresses(createHostsResolver()));
    //获取所有节点
    final DiscoveryNodes nodes = contextProvider.clusterState().nodes();
    // add all possible master nodes that were active in the last known cluster configuration
    for (ObjectCursor<DiscoveryNode> masterNode : nodes.getMasterNodes().values()) {
   
        seedAddresses.add(masterNode.value.getAddress());
    }

    final ConnectionProfile connectionProfile =
        ConnectionProfile.buildSingleChannelProfile(TransportRequestOptions.Type.REG, requestDuration, requestDuration,
                                                    TimeValue.MINUS_ONE, null);
    final PingingRound pingingRound = new PingingRound(pingingRoundIdGenerator.incrementAndGet(), seedAddresses, resultsConsumer,
                                                       nodes.getLocalNode(), connectionProfile);
    //记录ping结果
    activePingingRounds.put(pingingRound.id(), pingingRound);
    final AbstractRunnable pingSender = new AbstractRunnable() {
   
        @Override
        public void onFailure(Exception e) {
   
            if (e instanceof AlreadyClosedException == false) {
   
                logger.warn("unexpected error while pinging", e);
            }
        }

        @Override
        protected void doRun() throws Exception {
   
            //发送ping请求
            sendPings(requestDuration, pingingRound);
        }
    };
    //使用通用的的线程池执行
    threadPool.generic().execute(pingSender);
    //并且添加两个定时执行任务
    threadPool.schedule(pingSender, TimeValue.timeValueMillis(scheduleDuration.millis() / 3), ThreadPool.Names.GENERIC);
    threadPool.schedule(pingSender, TimeValue.timeValueMillis(scheduleDuration.millis() / 3 * 2), ThreadPool.Names.GENERIC);
    threadPool.schedule(new AbstractRunnable() {
   
        @Override
        protected void doRun() throws Exception {
   
            //结束ping,关闭资源
            finishPingingRound(pingingRound);
        }

        @Override
        public void onFailure(Exception e) {
   
            logger.warn("unexpected error while finishing pinging round", e);
        }
    }, scheduleDuration, ThreadPool.Names.GENERIC);
}

根据配置的单播地址构造需要发送请求的nodes,发送ping请求到node

protected void sendPings(final TimeValue timeout, final PingingRound pingingRound) {
   
    final ClusterState lastState = contextProvider.clusterState();
    final UnicastPingRequest pingRequest = new UnicastPingRequest(pingingRound.id(), timeout, createPingResponse(lastState));

    List<TransportAddress> temporalAddresses = temporalResponses.stream().map(pingResponse -> {
   
        assert clusterName.equals(pingResponse.clusterName()) :
        "got a ping request from a different cluster. expected " + clusterName + " got " + pingResponse.clusterName();
        return pingResponse.node().getAddress();
    }).collect(Collectors.toList());

    final Stream<TransportAddress> uniqueAddresses = Stream.concat(pingingRound.getSeedAddresses().stream(),
                                                                   temporalAddresses.stream()).distinct();

    // resolve what we can via the latest cluster state
    //单播node节点
    final Set<DiscoveryNode> nodesToPing = uniqueAddresses
        .map(address -> {
   
            DiscoveryNode foundNode = lastState.nodes().findByAddress(address);
            //检查节点之前是否连接过
            if (foundNode != null && transportService.nodeConnected(foundNode)) {
   
                return foundNode;
            } else {
   
                return new DiscoveryNode(
                    address.toString(),
                    address,
                    emptyMap(),
                    emptySet(),
                    Version.CURRENT.minimumCompatibilityVersion());
            }
        }).collect(Collectors.toSet
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值