Elasticsearch加入集群流程

本文深入分析了Elasticsearch节点如何加入集群的过程,涉及Bully算法和ZenDiscovery机制。从节点启动、选举流程到节点状态同步,详细解读了源码中的关键步骤和逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简介

es节点启动时,做的最重要的一件事就是加入集群,今天分析下es节点加入集群的源码。

主要知识点

es基础

基于lucene的分布式搜索引擎,不在累述,可以自行查阅资料。

Bully算法

提到分布式选举算法,大家都知道Paxos算法,但是这个算法比较复杂,es选取的是一个很简单的Bully算法,算法描述如下:

  1. 某个进程通过广播,获取所有能够连接到的进程的ID。
  2. 如果发现自己是ID最大的进程,则广播自己成为master节点,并广播该消息。
  3. 如果进程发现有其他进程比自己的ID大,则认为自己不能成为master,等待master广播。

整个选主流程非常简单,下面我们去es代码中一窥究竟。

代码分析

Node启动的时候做了很多事情,我们这次主要关注的涉及以下代码,discovery的默认实现是ZenDiscovery。

public Node start() throws NodeValidationException {
    ...
    // 启动Discovery,这个模块用来发现其他节点。
    discovery.start();
    transportService.acceptIncomingRequests();
    // 开始加入集群
    discovery.startInitialJoin();
    ...
}

ZenDiscovery是Es默认实现的节点发现服务,上面调用了startInitialJoin()方法:

@Override
public void startInitialJoin() {
    // start the join thread from a cluster state update. See {@link JoinThreadControl} for details.
    clusterService.submitStateUpdateTask("initial_join", new LocalClusterUpdateTask() {

        @Override
        public ClusterTasksResult<LocalClusterUpdateTask> execute(ClusterState currentState) throws Exception {
            // do the join on a different thread, the DiscoveryService waits for 30s anyhow till it is discovered
            joinThreadControl.startNewThreadIfNotRunning();                return unchanged();
        }

        @Override
        public void onFailure(String source, @org.elasticsearch.common.Nullable Exception e) {
            logger.warn("failed to start initial join process", e);
        }
    });
}

这里直接向clusterService提交了一个任务,在execute方法中,通过joinThreadControl来启动一个线程进行join。JoinThreadControl是ZenDistovery的内部类,主要用来控制join线程,保证只有一个线程执行join任务,以及join成功后的处理,这样可以使得startInitialJoin()方法迅速返回,不阻塞node节点的start方法。

下面来看下startNewThreadIfNotRunning()方法:

public void startNewThreadIfNotRunning() {
    ClusterService.assertClusterStateThread();
    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);
                    // Because we catch any exception here, we want to know in
                    // tests if an uncaught exception got to this point and the test infra uncaught exception
                    // leak detection can catch this. In practise no uncaught exception should leak
                    assert ExceptionsHelper.reThrowIfNotNull(e);
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值