Elasticsearch 节点选举和primary分片

前提概要

默认情况下,elasticsearch集群中每个节点都有成为master主节点的资格,也都可以存储数据,还可以对外提供查询服务。这些功能是由两个属性控制的— node.masternode.data。默认情况下这两个属性的值都是true。下面详细介绍一下这两个属性的含义以及不同组合可以达到的效果。

node.master 这个属性表示节点是否具有成为主节点的资格

注意:此属性的值为true,并不意味着这个节点就是主节点。因为真正的主节点,是由多个具有主节点资格的节点进行选举产生的。所以,这个属性只是代表这个节点是不是具有主节点选举资格。 下面会讨论如何被选举成为真正的主节点。

node.data 这个属性表示节点是否用来存储数据。

而这两个属性可以有以下四种组合:

1)      node.master: true  node.data: true

这种组合表示这个节点即有成为主节点的资格,又可以存储数据。这个时候如果某个节点被选举成为了真正的主节点,那么他还要存储数据,这样对于这个节点的压力就比较大。elasticsearch默认每个节点都是这样的配置,在测试环境下这样做没问题。实际生产环境下建议不要这样设置,这样相当于主节点和数据节点的角色混合到一块了。

2)      node.master: false  node.data: true

这种组合表示这个节点没有成为主节点的资格,也就不能参与选举,只会存储数据。这个节点我们称为data(数据)节点。在集群中需要单独设置几个这样的节点负责存储数据,后期提供存储和查询服务。

3)      node.master: true  node.data: false

这种组合表示这个节点不会存储数据,有成为主节点的资格,可以参与选举,有可能成为真正的主节点。这个节点我们称为master节点。

4)       node.master: false  node.data: false

这种组合表示这个节点即不会成为主节点,也不会存储数据,这个节点的意义是作为一个client(客户端)节点,主要是针对海量请求的时候可以进行负载均衡。

默认情况下,每个节点都有成为主节点的资格,也会存储数据,还会处理客户端的请求。在一个生产集群中我们可以对这些节点的职责进行划分。

Master 选举

Master 主节点作为cluster的灵魂必须要有,还必须要唯一,否则集群就出大问题了,关于分布式系统的master 选举算法有很多,最有名的当然要数paxos算法,在它的基础上出现了非常多的变体算法。但是paxos的功能远远超出了master选举,一致性才是它的目标,任何需要实现一致性的问题都可以使用该算法。集群有一个问题就是brain split:一个集群因为网络问题导致多个master主节点选举出来而分裂。这也是master选举必须要解决的问题。

具体原理如下(下面的master节点即为主节点):

1)      对所有可以成为master的节点根据 nodeId排序,每次选举每个节点都把自己所知道节点排一次序,然后选出第一个(第0位)节点,暂且认为它是master节点;

2)      如果对某个节点的投票数达到一定的值(可以成为master节点数n/2+1)并且该节点自己也选举自己,那这个节点就是master。否则重新选举;

3)      对于brain split问题,需要把候选master节点最小值设置为可以成为master节点数n/2+1;

以上就是master选举的三条原则,其实第三条包含在第二条之中,为了说明brain split问题这里单独拿出来说一下。

下面看一下ElectMasterService的相关代码,来补充说明一下上面的文字描述:

public DiscoveryNode electMaster(Iterable nodes) {

        List sortedNodes = sortedMasterNodes(nodes);

        if (sortedNodes == null || sortedNodes.isEmpty()) {

            return null ;

        }

        return sortedNodes. get ( 0 );

    }

上面就是选举master的方法。可以看到,它的做法就是对候选节点排序然后直接将第一个返回。当然这只是上面所说的第一条。如果每个节点都只是选举自己排序后的节点的第一个肯定会导致brain split和选举不一致。

master 比较的方法也比较简单如下所示:

private static class NodeComparator implements Comparator {

 

        @Override

        public int compare(DiscoveryNode o1, DiscoveryNode o2) {

            if (o1.masterNode() && !o2.masterNode()) {

                return - 1 ;

            }

            if (!o1.masterNode() && o2.masterNode()) {

                return 1 ;

            }

            return o1.id().compareTo(o2.id());

        }

    }

以上是节点排序比较器。可以看到它只是比较了nodeId,因此是按nodeId排序。

为了解决brain split问题加入了master候选数量限制,代码如下:

    public boolean hasEnoughMasterNodes(Iterable nodes) {

        if (minimumMasterNodes < 1 ) {

            return true ;

        }

        int count = 0 ;

        for (DiscoveryNode node : nodes) {

            if (node.masterNode()) {

                count++;

            }

        }

        return count >= minimumMasterNodes;

    }

通过比较节点能“看到”的候选master数量和配置的最小值来确定是否可以进行选举,如果数量不够会导致选举不能进行,这样就可以保证集群不会被分裂。

下面以一个图(图片来自于elasticsearch官网)来说明:

假设之前选举了A节点为master,两个switch之间突然断线了,这样就分成了两部分,CDE和AB。因为 minimumMasterNodes的数目为3(集群中5个节点都可以成为master,3=5/2+1),因此CDE会可以进行选举,假设C成为master。AB两个节点因为少于3所以无法选举,只能一直寻求加入集群,要么线路连通加入到CDE中要么就一直处于寻找集群状态,这样就保证了集群不分裂。

Shard 机制

单台机器无法存储大量数据,elasticsearch可以将一个索引中的数据切分为多个shard(一个index包含多个shard ),分布在多台服务器上存储。有了shard就可以横向扩展,存储更多数据,让搜索和分析等操作分布到多台服务器上去执行,提升吞吐量和性能。每个shard都是一个lucene index。

shard 分为两类:

primary shard 主分片,承担 读写请求负载;

replica shard 副本分片,是主分片的副本,负责容错,以及承担 请求负载;

任何一台服务器随时可能故障或宕机,此时shard可能就会丢失,因此可以为每个shard创建多个replica副本。replica可以在shard故障时提供备用服务,保证数据不丢失,多个replica还可以提升搜索操作的吞吐量和性能。

Shard 主要特性:

1)      index 包含多个shard;

2)      每个shard都是一个最小工作单元,承载部分数据,lucene实例,完整的建立索引和处理请求的能力;

3)      增减节点时,shard会自动在nodes中负载均衡;

4)      primary shard 和replica shard,每个document肯定只存在于某一个primary shard以及其对应的replica shard中,不可能存在于多个primary shard;

5)      replica shard 是primary shard的副本,负责容错,以及承担读请求负载;

6)      primary shard 的数量在创建索引的时候就固定了,replica shard的数量可以随时修改;

7)      primary shard 的默认数量是5,replica默认是1,默认有10个shard,5个primary shard,5个replica shard;

8)      primary shard 不能和自己的replica shard放在同一个节点上 (否则节点宕机,primary shard和副本都丢失,起不到容错的作用),但是可以和其他primary shard的replica shard放在同一个节点上;

primary shard 宕机后,新master将某个replica shard提升为primary shard。重启宕机node,master copy replica到该node,使用原有的shard并同步宕机后的修改。原有的primary shard降级为replica shard

假设有3个节点,9个shard (3个primary shard,每个 primary shard 有 2 个 replica shard),具体分配如下表,假设 Node1 为 master

Node1

Node2

Node3

P0 , P1-1 , P2-1

P1 , P0-1 , P2-2

P2 , P1-2 , P0-2

如果 Node1 宕机,此时集群状态为 red, 集群会自动选举一个节点为新的 master 主节点(假设为 Node2)。

新的 master Node2 将 P0-1 这个 replica shard 升级成 primary shard, 此时 集群状态为 yellow。

重新启动 Node1 节点, 会自动更新数据,此时集群状态为 green。

 

建议

集群中设置3台以上的节点作为master节点【node.master: true  node.data: false】。这些节点只负责成为主节点,维护整个集群的状态。

再根据数据量设置一批data节点【node.master: false  node.data: true】。这些节点只负责存储数据。

后期提供建立索引和查询索引的服务,如果用户请求比较频繁,这些节点的压力也会比较大。所以在集群中建议再设置一批client节点【node.master: false  node.data: false】。这些节点只负责处理用户请求,实现请求转发,负载均衡等功能。

配置要求

master 节点:普通服务器即可(CPU、内存 消耗一般);

data 节点:主要消耗磁盘,内存;

client 节点:普通服务器即可(如果要进行分组聚合操作的话,建议这个节点内存也分配多一点)。

 


请使用浏览器的分享功能分享到微信等