elasticsearch的master选举

Posted penriver

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了elasticsearch的master选举相关的知识,希望对你有一定的参考价值。

1 Discovery

Discovery模块负责发现集群中的节点、选择主节点。
ES支持多种不同Discovery类型选择,内置的实现有两种:Zen Discovery和Coordinator
7.x以上版本Coordinator提供了安全的亚秒级的master选举时间,而Zen可能要花几秒钟来选择一个新的master

涉及的核心配置如下,其它配置参数,参见: master-election-settings

  • discovery.seed_hosts: 提供群集中符合master-eligible的节点地址列表
  • cluster.initial_master_nodes : 设置全新集群中符合主节点条件的初始节点集。默认情况下,此列表为空,这意味着该节点希望加入已经bootstrap的集群

ES集群中可能会有多个master-eligible node,在集群启动时需要进行master选举,保证只有一个当选master。如果有多个node当选为master,则集群会出现脑裂,脑裂会破坏数据的一致性,导致集群行为不可控,产生各种非预期的影响。

1.1 Coordinator

ES 7.x 重构了一个新的集群协调层Coordinator,采用 Raft 的实现,但并非严格按照 Raft 论文实现,而是根据ES做了一些调整

使用的算法可以在配置中指定,详见代码如下:
org.elasticsearch.discovery.DiscoveryModule.DiscoveryModule的构造函数

 if (ZEN2_DISCOVERY_TYPE.equals(discoveryType) || SINGLE_NODE_DISCOVERY_TYPE.equals(discoveryType)) {
            discovery = new Coordinator(NODE_NAME_SETTING.get(settings),
                settings, clusterSettings,
                transportService, namedWriteableRegistry, allocationService, masterService,
                () -> gatewayMetaState.getPersistedState(settings, (ClusterApplierService) clusterApplier), seedHostsProvider,
                clusterApplier, joinValidators, new Random(Randomness.get().nextLong()));
        } else if (ZEN_DISCOVERY_TYPE.equals(discoveryType)) {
            discovery = new ZenDiscovery(settings, threadPool, transportService, namedWriteableRegistry, masterService, clusterApplier,
                clusterSettings, seedHostsProvider, allocationService, joinValidators, gatewayMetaState);
        } else {
            throw new IllegalArgumentException("Unknown discovery type [" + discoveryType + "]");
        }

1.2 Zen Discovery

采用Bully算法 Bully算法是Leader选举的基本算法之一,优点是易于实现,该算法和Solr Leader Shard选举非常相似。
该算法假定所有节点都有一个唯一的ID,使用该ID对节点进行排序,选择最小的节点作为Master
任何时候当前Leader都是参与集群的最小ID节点。该算法的优点是易于实现。

但是当拥有最小ID的节点处于不稳定状态的场景下会有问题。例如Master负载过重而假死,集群拥有第二小ID的节点被选为新主,这时原来的Master恢复,再次被选为新主,然后又假死。

ES 通过推迟选举,直到当前的 Master 失效来解决上述问题,只要当前主节点不挂掉,就不重新选主。但是容易产生脑裂(双主),为此,再通过“法定得票人数过半”解决脑裂问题

1.3 算法比较【raft & bully】

相同点

  • 多数派原则:必须得到超过半数的选票才能成为master。
  • 选出的leader一定拥有最新已提交数据:在raft中,数据更新的节点不会给数据旧的节点投选票,而当选需要多数派的选票,则当选人一定有最新已提交数据。在es中,clusterStateVersion大的节点排序优先级高,同样用于保证这一点。

不同点

  • 正确性论证:raft是一个被论证过正确性的算法,而ES的算法是一个没有经过论证的算法,只能在实践中发现问题,做bug fix,这是我认为最大的不同。
  • 是否有选举周期term:raft引入了选举周期的概念,每轮选举term加1,保证了在同一个term下每个参与人只能投1票。ES在选举时没有term的概念,不能保证每轮每个节点只投一票。
  • 选举的倾向性:raft中只要一个节点拥有最新的已提交的数据,则有机会选举成为master。在ES中,version相同时会按照NodeId排序,总是NodeId小的人优先级高。

2 Zen Discovery选举

2.1 何时触发

  • 集群启动,从无主状态到产生新主时
  • 集群在正常运行过程中,Master探测到节点离开时(NodesFaultDetection)
  • 集群在正常运行过程中,非Master节点探测到Master离开时(MasterFaultDetection)

2.2 选举谁

从源码分析,选举集群状态版本最高的作为master

先根据节点的clusterStateVersion比较,clusterStateVersion越大,优先级越高。clusterStateVersion相同时,进入compareNodes,其内部按照节点的Id比较(Id为节点第一次启动时随机生成)。

选举集群状态版本最高的作为master的原因如下:

  • 为了保证新Master拥有最新的clusterState(即集群的meta),避免已经commit的meta变更丢失。因为Master当选后,就会以这个版本的clusterState为基础进行更新。
  • 当clusterStateVersion相同时,节点的Id越小,优先级越高。即总是倾向于选择Id小的Node,这个Id是节点第一次启动时生成的一个随机字符串。之所以这么设计,应该是为了让选举结果尽可能稳定,不要出现都想当master而选不出来的情况。

参见ElectMasterService类中的这2个方法

 /**
     * Elects a new master out of the possible nodes, returning it. Returns {@code null}
     * if no master has been elected.
     */
    public MasterCandidate electMaster(Collection<MasterCandidate> candidates) {
        assert hasEnoughCandidates(candidates);
        List<MasterCandidate> sortedCandidates = new ArrayList<>(candidates);
        sortedCandidates.sort(MasterCandidate::compare);
        return sortedCandidates.get(0);
    }

		/**
         * compares two candidates to indicate which the a better master.
         * A higher cluster state version is better
         *
         * @return -1 if c1 is a batter candidate, 1 if c2.
         */
        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;
        }

2.3 选举流程

代码详见:ZenDiscovery的findMaster()方法

  1. ping所有节点,并获取PingResponse返回结果(findMaster)
  2. 过滤出具有Master资格的节点(filterPingResponses)并转换为masterCandidates
  3. 选出临时Master。根据PingResponse结果构建两个列表:activeMasters和masterCandidates。
    3.1. 如果activeMasters非空,则从activeMasters中选择最合适的作为Master;
    3.2. 如果activeMasters为空,则从masterCandidates中选举,结果可能选举成功,也可能选举失败。
  4. 判断临时Master是否是本节点。
    4.1. 如果临时Master是本节点:则等待其他节点选我,默认30秒超时,成功的话就发布新的clusterState。(当选总统候选人,只等选票过半了)
    4.2. 如果临时Master是其他节点:则不再接受其他节点的join请求,并向Master节点发送加入请求

3 节点失效检测

选主流程之后不可或缺的步骤,不执行失效检测可能会产生脑裂现象。
定期(默认为1s)发送ping请求探测节点是否正常,当失败达到一定次数(默认为3次),或者收到节点的离线通知时,开始处理节点离开事件。

3.1 NodesFaultDetection

NodesFaultDetection在Master节点启动。定期探测加入集群的节点是否活跃。当有节点连不上时,会执行removeNode。然后需要审视此时的法定人数是否达标,不达标就主动放弃Master身份执行rejoin以避免脑裂。

3.2 MasterFaultDetection

MasterFaultDetection在非Master节点启动。定期探测Master节点是否活跃,Master下线则触发rejoin重新选举。

参考

found-leader-election-in-general#the-zen-way
modules-discovery-settings.html#master-election-settings
Elasticsearch选主流程

以上是关于elasticsearch的master选举的主要内容,如果未能解决你的问题,请参考以下文章

Elasticsearch 是如何实现 Master 选举的?

Elasticsearch 是如何实现 Master 选举的?

elasticsearch的master选举

Elasticsearch是如何实现master选举的?

Elasticsearch 是如何实现Master 选举的?

Elasticsearch的集群容错机制以及选举机制