elastic elasticsearch 源码解析之选主选举过程

这篇具有很好参考价值的文章主要介绍了elastic elasticsearch 源码解析之选主选举过程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

选主

选举算法

角色定义

这里的选主为什么提角色? 是因为不同角色在选主中起到不同的作用.master的非voting_only节点不但参与投票同时还可以参与竞选, master 的voting_only角色仅投票不参与竞选,其余角色不参与.

支持的角色

master
data
data_content
data_hot
data_warm
data_cold
data_frozen
ingest
ml
remote_cluster_client
transform

如果不设置node.roles 则默认有所有角色, 如果配置了,以配置的为准.

remote_cluster_client跨集群搜索和副本角色

只有master角色才允许voting_only

高可用集群最少需要3个master

data角色如果分层的话,又可以分为

data_content,data_hot,data_warm,data_cold,或data_frozen

不同的层在存储时间,是否压缩,访问性能等进行差异化管理.以达到空间和性能的最优化.

法定人数机制

. 法定人数一般大于半数,主要目的是提高集群健壮性同时要避免脑裂问题.这个数值一般是多少? 一般

  • 奇数投票节点
  • n/2+1个quorum

正常情况quorum等于候选节点+投票节点之和

选举完成之后提交集群状态

选主协议

选主协议应该包含至少4个部分

  • 检测

  • 发起

  • 选主核心逻辑(互斥和一致性)

  • 发布状态

先发起的会成功,如果同时发起则失败.依据是什么? 时间戳?

为了避免选举冲突每个节点发起选举流程都是随机调度.

检测

一般提供两种, 一种检测master, 一种检测node, 一般通过ping,默认1s,连续失败3次判定节点失效.

发起

当检测判定主节点失效则会发起投票

选主核心逻辑

如何避免冲突?

  • 如果发现节点不是自己,则加入. 所以即使同时发起选举也不影响,大家会加入相同的集群,除非发生脑裂分区等异常

如何避免脑裂?

  • 检查自己集群法定人数如果自己集群法定人数(过半),则放弃,重新加入其他集群.这个主要是避免脑裂

选举常见问题

增减节点同步信息未完成发生选举

如果增减节点同步信息未完成发生选举,是否有不一致和集群可用性问题

投票设置

增减节点动态调整

增减节点动态调整投票配置,以增强集群的弹性

这个一般发生增减节点时,通过自动通信机制来实现.

节点数

一般需要奇数

如果不是奇数它会取消一个节点的选举权

奇数某些情况可以提高网络分区可用性问题

比如4个节点集群, 会有3个候选节点, 法定投票人数最少是2,那么一旦分区之后,至少有个一个分区包含2个节点,这时候仍然是可用的

如果每个节点配置的集群期望节点数不一致会导致什么问题?

数据丢失.这种场景一般发生在初次启动时, 已经启动之后因为有节点发现协议,它会慢慢的读取到正确的节点.

对集群来说它自己没法提供一个完全安全的引导启动配置, 即使所有节点的引导启动配置一致,也无法保证集群完全安全的启动.比如这样一个有4台node的集群,他们通过自动化同时启动很可能造成分区.因为4个node,只能有奇数(3)个node有投票权, 那么2个node投票就可以形成集群(如果是通过集群动态调整投票节点的话, 如果你固定配置某个节点没有投票权当然可以避免)

所以quorum是集群启动的必选项.

选主流程

选举临时Master->[本节点是Master?确人orelse加入]->启动NodeFD OR 启动MasterFD

为什么选举临时Master

需要足够票数

临时Master选举流程

ping所有节点->获取所有节点reposne+本节点也加入response->构建两个列表activeMaster和(活跃的Master节点)

正常情况activeMaster只能有一个,这里为什么是列表, 因为可能存在不一致情况.并且构建active master过程中如果节点不具备资格根据配置ignore_non_master_pings会忽略.

另一个要维护的列表是masterCandidates

两个列表构建完成之后, 如果没有active master则从候选master列表选择进行选举

选举临时Master

它的选主逻辑很简单就是从节点找出版本最高的然后最小的节点. 源码对应的方法是electMaster

    public MasterCandidate electMaster(Collection<MasterCandidate> candidates) {
        assert hasEnoughCandidates(candidates);
        List<MasterCandidate> sortedCandidates = new ArrayList<>(candidates);
        sortedCandidates.sort(MasterCandidate::compare);
        return sortedCandidates.get(0);
    }
				// 取version最大及节点最小的作为主节点
        public static int compare(MasterCandidate c1, MasterCandidate c2) {
            // we explicitly swap c1 and c2 here. the code expects "better" is lower in a sorted
            // list, so if c2 has a higher cluster state version, it needs to come first.
            int ret = Long.compare(c2.clusterStateVersion, c1.clusterStateVersion);
            if (ret == 0) {
                ret = compareNodes(c1.getNode(), c2.getNode());
            }
            return ret;
        }

但是从源码我们看出来, 它没有判断角色,其实候选master是需要对应角色的. 这块的逻辑是怎么样的?

    /** master nodes go before other nodes, with a secondary sort by id **/
    private static int compareNodes(DiscoveryNode o1, DiscoveryNode o2) {
      	// 优先选择是master node的节点
        if (o1.isMasterNode() && o2.isMasterNode() == false) {
            return -1;
        }
        if (o1.isMasterNode() == false && o2.isMasterNode()) {
            return 1;
        }
      	
      // 如果都是或者都不是再比较节点id,取小的
        return o1.getId().compareTo(o2.getId());
    }

那么我们可能会有个疑问不具备master角色的节点为什么有资格参与竞选主节点呢? 其实这部分逻辑主要是为了列表排序,并不是真正的选主,选主逻辑会判断它是否具备资格. 那为什么不在这里直接过滤呢?

我能回答的是,它有过滤但是没有在这里过滤

ZenDiscovery#handleJoinRequest->NodeJoinController.ElectionContext#getPendingMasterJoinsCount
  
   public synchronized int getPendingMasterJoinsCount() {
            int pendingMasterJoins = 0;
            for (DiscoveryNode node : joinRequestAccumulator.keySet()) {
              	// 这个逻辑是用来判定候选节点数是否达到法定人数的, 在这里排除掉了非master节点, 但是如果非master节点依然在候选列表中
                if (node.isMasterNode()) {
                    pendingMasterJoins++;
                }
            }
            return pendingMasterJoins;
        }

如果候选节点是自己

(1) 等待节点加入自己集群

(2) 超时重新选举

(3) 成功发布通知

    private void innerJoinCluster() {
        ...
				// 如果临时Master是本节点
        if (transportService.getLocalNode().equals(masterNode)) {
            final int requiredJoins = Math.max(0, electMaster.minimumMasterNodes() - 1); // we count as one
            // 等待足够多的具备Master资格的节点加入本节点(投票达到法定人数),以完成选举。
            nodeJoinController.waitToBeElectedAsMaster(
                requiredJoins,
              // 超时(默认为30秒,可配置)后还没有满足数量的join请求,则选举失败,需要进行新一轮选举。
                masterElectionWaitForJoinsTimeout,
                new NodeJoinController.ElectionCallback() {
                  	// 成功后发布新的clusterState。
                    @Override
                    public void onElectedAsMaster(ClusterState state) {
                        synchronized (stateMutex) {
                            joinThreadControl.markThreadAsDone(currentThread);
                        }
                    }

                    @Override
                    public void onFailure(Throwable t) {
                        ...
                    }
                }

            );
        } else {
          ...
        }
    }

如果不是自己

如果其他节点被选为Master:

(1) 停止接受节点加入自己集群请求

(2) 发起加入其他节点集群请求

(3)等待回复文章来源地址https://www.toymoban.com/news/detail-604603.html

    private void innerJoinCluster() {
        ...
        if (transportService.getLocalNode().equals(masterNode)) {
          ...
        } else {
            // process any incoming joins (they will fail because we are not the master)
            // 不再接受其他节点的join请求
            nodeJoinController.stopElectionContext(masterNode + " elected");

            // send join request
          //向Master发送加入请求,并等待回复。超时时间默认为1分钟(可配置),如果遇到异常,则默认重试3次(可配置)。这个步骤在joinElectedMaster方法中实现。
            final boolean success = joinElectedMaster(masterNode);
						// 最终当选的Master会先发布集群状态,才确认客户的join请求,因此,joinElectedMaster返回代表收到了join请求的确认,并且已经收到了集群状态。本步骤检查收到的集群状态中的Master节点如果为空,或者当选的Master不是之前选择的节点,则重新选举。
            synchronized (stateMutex) {
                if (success) {
                    DiscoveryNode currentMasterNode = this.clusterState().getNodes().getMasterNode();
                    if (currentMasterNode == null) {
                        // Post 1.3.0, the master should publish a new cluster state before acking our join request. we now should have
                        // a valid master.
                        logger.debug("no master node is set, despite of join request completing. retrying pings.");
                        joinThreadControl.markThreadAsDoneAndStartNew(currentThread);
                    } else if (currentMasterNode.equals(masterNode) == false) {
                        // update cluster state
                        joinThreadControl.stopRunningThreadAndRejoin("master_switched_while_finalizing_join");
                    }

                    joinThreadControl.markThreadAsDone(currentThread);
                } else {
                    // failed to join. Try again...
                    joinThreadControl.markThreadAsDoneAndStartNew(currentThread);
                }
            }
        }
    }

到了这里,关于elastic elasticsearch 源码解析之选主选举过程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 30、OSPF路由协议工作过程及DR和BDR选举方法

    OSPF(Open Shortest Path First开放式最短路径优先)是一个内部网关协议(Interior Gateway Protocol,简称IGP),用于在单一自治系统(autonomous system,AS)内决策路由。是对链路状态路由协议的一种实现,隶属内部网关协议(IGP),故运作于自治系统内部。著名的迪克斯加算法被用来计算最

    2024年02月15日
    浏览(32)
  • 【Elasticsearch专栏 16】深入探索:Elasticsearch的Master选举机制及其影响因素分析

    Elasticsearch,作为当今最流行的开源搜索和分析引擎,以其分布式、可扩展和高可用的特性赢得了广大开发者的青睐。在Elasticsearch的分布式架构中,集群的稳健性和高可用性很大程度上依赖于其Master节点的选举机制。本文将深入剖析Elasticsearch的Master选举过程,帮助读者更好地

    2024年04月17日
    浏览(28)
  • Spring源码解析——ApplicationContext容器refresh过程

    正文 在之前的博文中我们一直以BeanFactory接口以及它的默认实现类XmlBeanFactory为例进行分析,但是Spring中还提供了另一个接口ApplicationContext,用于扩展BeanFactory中现有的功能。 ApplicationContext和BeanFactory两者都是用于加载Bean的,但是相比之下,ApplicationContext提供了更多的扩展功

    2024年02月08日
    浏览(46)
  • zookeeper选举流程源码分析

    zookeeper选举流程源码分析 选举的代码主要是在 QuorumPeer.java 这个类中。 它有一个内部枚举类,用来表示当前节点的状态。 LOOKING: 当前节点在选举过程中 FOLLOWING:当前节点是从节点 LEADING: 当前节点是主节点 OBSERVING: 当前节点是观察者状态,这种状态的节点不参与选举的投

    2024年02月11日
    浏览(29)
  • etcd/raft选举源码解读

    该篇博客基于etcd v3.5.7版本,首先会简单介绍etcd/raft对Raft选举部分的算法优化,然后通过源码分析etcd/raft的选举实现。 该优化措施均在raft博士论文中有讲解 etcd/raft实现的与选举有关的优化有 Pre-Vote 、 Check Quorum 、和 Leader Lease 。在这三种优化中,只有 Pre-Vote 和 Leader Lease 最

    2023年04月08日
    浏览(18)
  • zookeeper源码(04)leader选举流程

    在\\\"zookeeper源码(03)集群启动流程\\\"中介绍了leader选举的入口,本文将详细分析leader选举组件和流程。 quorumPeer的start阶段使用startLeaderElection()方法启动选举 LOOKING状态,投自己一票 createElectionAlgorithm - 创建选举核心组件:QuorumCnxManager(管理连接)、FastLeaderElection(选举)等 quorumPeer的

    2024年02月05日
    浏览(30)
  • Unity 之 接入IOS内购过程解析【文末源码】

    看完此文章你可以了解IOS内购接入全过程,可以学习到Unity从零接入内购功能。另外此博文和文末源码没有涉及到掉单补单部分逻辑。 一台mac系统机器 苹果开发者账号 Unity2019.4.x (不同版本,3步骤略有不同) Xcode (我的版本12.5) PS:若公司已有运营人员在后台操作过了,可以

    2023年04月17日
    浏览(24)
  • 浅谈Zookeeper集群选举Leader节点源码

    写在前面: zookeeper源码比较复杂,本文讲解的重点为各个zookeeper服务节点之间的state选举。至于各个节点之间的数据同步,不在文本的侧重讲解范围内。 在没有对zookeeper组件有一个整体架构认识的基础上,不建议直接死磕细节。本文写作的目的也是基于此,阅读本文,希望读

    2024年02月07日
    浏览(34)
  • Elasticsearch 8.9启动时构建接收Rest请求的hander过程源码

    路径: org.elasticsearch.bootstrap.Elasticsearch 这里初始化会有三个初始化阶段。可以直接看 initPhase3 其中 INSTANCE.start(); 如下,代表node启动,并且存活线程运行 其中调用 RestHandler 接口的 handerRequest 的上游是 其他注册在 hander 中的API和 RestGetIndicesAction 类似

    2024年02月07日
    浏览(30)
  • 【源码解析】flink sql执行源码概述:flink sql执行过程中有哪些阶段,这些阶段的源码大概位置在哪里

    本文大致分析了flink sql执行过程中的各个阶段的源码逻辑,这样可以在flink sql执行过程中, 能够定位到任务执行的某个阶段的代码大概分布在哪里,为更针对性的分析此阶段的细节逻辑打下基础,比如create 的逻辑是怎么执行的,select的逻辑是怎么生成的,优化逻辑都做了哪

    2024年02月04日
    浏览(28)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包