(四)ElasticSearch 集群

集群

  一个运行中的 Elasticsearch 实例称为一个节点,而集群是由一个或者多个拥有相同 cluster.name 配置的节点组成, 它们共同承担数据和负载的压力。

  当有节点加入集群中或者从集群中移除节点时,集群将会重新平均分布所有的数据。

  当一个节点被选举成为主节点时,它将负责管理集群范围内的所有变更,例如增加、删除索引,或者增加、删除节点等。 而主节点并不需要涉及到文档级别的变更和搜索等操作,所以当集群只拥有一个主节点的情况下,即使流量的增加它也不会成为瓶颈。 任何节点都可以成为主节点。
  作为用户,我们可以将请求发送到集群中的任何节点 ,包括主节点。
  每个节点都知道任意文档所处的位置,并且能够将我们的请求直接转发到存储我们所需文档的节点。
  无论我们将请求发送到哪个节点,它都能负责从各个包含我们所需文档的节点收集回数据,并将最终结果返回給客户端。 Elasticsearch 对这一切的管理都是透明的。

集群健康

  Elasticsearch 的集群监控信息中包含了许多的统计数据,其中最为重要的一项就是集群健康信息 , 它在 status 字段中展示为 greenyellow 或者 red

1
GET /_cluster/health

  在一个不包含任何索引的空集群中,它将会有一个类似于如下所示的返回内容:

1
2
3
4
5
6
7
8
9
10
11
12
{
"cluster_name": "elasticsearch",
"status": "green",
"timed_out": false,
"number_of_nodes": 1,
"number_of_data_nodes": 1,
"active_primary_shards": 0,
"active_shards": 0,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 0
}

  其中,status 字段最重要,它指示着当前集群在总体上是否工作正常。
  status 字段的三种颜色含义如下:

  • green:所有的主分片和副本分片都正常运行
  • yellow:所有的主分片都正常运行,但不是所有的副本分片都正常运行
  • red:存在主分片未正常运行

集群角色

  在高可用系统架构中,节点角色发挥着至关重要的作用。

  在 ES 集群中,不同的节点拥有不同的角色,那么,这些角色包含几种呢?

  ES 中节点的角色很多,常见角色如下

活跃主节点

活跃主节点(active master):一般指活跃的主节点,一个集群中只能有一个,主要作用是对集群的管理。

候选主节点

候选主节点(master一eligible):当主节点发生故障时参与选举,即主节点的替代节点
默认情况下,候选节点默认也是有效的投票节点,即:配置了master角色的节点,默认具备选举权和被选举权,可以参与选举,也可以为其他节点投票。
活跃的主节点一定是配置了master角色的节点,即一定是候选节点,但是候选节点不一定是主节点,一个集群中只可能有一个主节点,而可以同时存在多个候选节点,候选节点的作用主要在于当主节点宕机或发生故障脱离集群时,参与选举成为新的主节点,从而避免集群无主。
任何不是仅投票节点的主合格节点都可以通过主选举过程选举成为主节点

数据节点

数据节点(data node):数据节点保存包含已编入索引的文档的分片。数据节点处理数据相关操作,如 CRUD、搜索和聚合。这些操作是 I/O 密集型、内存密集型和 CPU 密集型的。监控这些资源并在它们过载时添加更多数据节点非常重要

预处理节点

预处理节点(ingest node):预处理节点有点类似于 logstash 的消息管道,所以也叫 ingest pipeline,常用于一些数据写 入之前的预处理操作

使用和配置方法

  准确的说,应该叫节点角色,是区分不同功能节点的一项服务配置,配置方法为

  注意:如果 node.roles 为缺省配置,那么当前节点具备所有角色

集群核心配置

  • network.host: 即提供服务的内网集群 ip 地址,一般配置为本节点所在服务器的内网地址,此配置会导致节点由开发模式转为生产模式,从而触发引导检查。
  • network.publish.host: 即提供服务的 ip 地址, 一般配置为本节点所在服务器的公网地址,搭建公网集群时使用,一般集群不会搭建公网,
  • http.port:服务端口号,默认 9200,通常范围为 9200~9299
  • transport.port: 集群节点通信端口,默认 9300,通常范围为 9300~9399
  • discovery.seed_hosts: 此设置提供集群中候选节点(master角色)的列表,并且可能处于活动状态且可联系以播种发现过程。地址可以是 IP ,也可以是主机
  • cluster.initial_master_nodes: 指定集群初次选举中用到的候选节点,称为集群引导,只在第一次形成集群时需要,如过配置了network.host, 则此配置项必须配置。重新启动节点或将新节点添加到现有集群时不要使用此设置

单节点集群

  我们往 Elasticsearch 添加数据时需要用到索引索引是保存相关数据的地方。
  实际上,索引是指向一个或者多个物理分片逻辑命名空间

  一个 分片 是一个底层的 工作单元 ,它仅保存了全部数据中的一部分。 在分片内部机制中,我们将详细介绍分片是如何工作的,而现在我们只需知道一个分片是一个 Lucene 的实例,以及它本身就是一个完整的搜索引擎。 我们的文档被存储和索引到分片内,但是应用程序是直接与索引而不是与分片进行交互。

  Elasticsearch 是利用分片将数据分发到集群内各处的。
  分片是数据的容器,文档保存在分片内,分片又被分配到集群内的各个节点里。
  当集群规模扩大或者缩小时, Elasticsearch 会自动的在各节点中迁移分片,使得数据仍然均匀分布在集群里。

  一个分片可以是分片或者副本分片。
  索引内任意一个文档都归属于一个主分片,所以主分片的数目决定着索引能够保存的最大数据量。

  技术上来说,一个主分片最大能够存储 Integer.MAX_VALUE - 128 个文档,但是实际最大值还需要参考你的使用场景:包括你使用的硬件, 文档的大小和复杂程度,索引和查询文档的方式以及你期望的响应时长。

  一个副本分片只是一个主分片的拷贝。副本分片作为硬件故障时保护数据不丢失的冗余备份,并为搜索和返回文档等读操作提供服务。

  在索引建立的时候就已经确定了主分片数,但是副本分片数可以随时修改。

  让我们在包含一个空节点的集群内创建名为 blogs 的索引。
  在默认情况下,索引会被分配 5 个主分片, 但是为了演示目的,我们将分配 3 个主分片和对应的一份副本(每个主分片拥有一个副本分片):

1
2
3
4
5
6
7
PUT /blogs
{
"settings" : {
"number_of_shards" : 3,
"number_of_replicas" : 1
}
}

  我们的集群现在是 “拥有一个索引的单节点集群”,所有 3 个主分片都被分配在 Node 1 。如下图:

拥有一个索引的单节点集群

  若我们现在查询集群健康情况,将看到如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"cluster_name": "elasticsearch",
"status": "yellow",
"timed_out": false,
"number_of_nodes": 1,
"number_of_data_nodes": 1,
"active_primary_shards": 3,
"active_shards": 3,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 3,
"delayed_unassigned_shards": 0,
"number_of_pending_tasks": 0,
"number_of_in_flight_fetch": 0,
"task_max_waiting_in_queue_millis": 0,
"active_shards_percent_as_number": 50
}

  集群 status 值为 yellow,这代表所有的分片都正常运行(集群可以正常服务所有请求),但是副本分片没有全部处在正常状态。
  为什么会这样呢?
  实际上,所有的 3 个副本分片都是 unassigned —— 都未被分配到任何节点。
  因为在同一个节点上既保存原始数据又保存副本是没有意义的,因此,一旦失去了那个节点,我们也将丢失该节点上的所有副本数据。

  当然,我们的集群能是正常运行的,但是在硬件故障时有丢失数据的风险。

故障转移

  当集群中只有一个节点在运行时,意味着会有一个单点故障问题——没有冗余。
  幸运的是,我们只需再启动一个节点即可防止数据丢失。

  若再启动第二个节点,集群将会如下图所示:

拥有两个节点的集群——所有主分片和副本分片都已被分配

  当第二个节点加入到集群后,3个 副本分片 将会分配到这个节点上——每个主分片对应一个副本分片。
  这意味着当集群内任何一个节点出现问题时,我们的数据都完好无损。

  所有新近被索引的文档都将会保存在主分片上,然后被并行的复制到对应的副本分片上
  这就保证了我们既可从主分片又可从副本分片上获得文档。

  若我们现在查询集群健康情况,将看到如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"cluster_name": "elasticsearch",
"status": "green",
"timed_out": false,
"number_of_nodes": 2,
"number_of_data_nodes": 2,
"active_primary_shards": 3,
"active_shards": 6,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 0,
"delayed_unassigned_shards": 0,
"number_of_pending_tasks": 0,
"number_of_in_flight_fetch": 0,
"task_max_waiting_in_queue_millis": 0,
"active_shards_percent_as_number": 100
}

  cluster-health 现在展示的status 值为 green ,这表示所有 6 个分片(包括 3 个主分片和 3 个副本分片)都正常运行。
  因此,集群现在不仅仅是正常运行的,并且还处于始终可用的状态。

水平扩容——性能提升

  怎样为我们的正在增长中的应用程序按需扩容呢?
  当启动了第三个节点,我们的集群将会变化成下图的样子:

拥有三个节点的集群——为了分散负载而对分片进行重新分配

  Node 1Node 2 上各有一个分片被迁移到了新的 Node 3 节点,现在每个节点上都拥有 2 个分片,而不是之前的 3 个。
  由于每个节点的硬件资源(CPU, RAM, I/O)将被更少的分片所共享,因此每个分片的性能将会得到提升。

  分片是一个功能完整的搜索引擎,它拥有使用一个节点上的所有资源的能力。
  集群现在拥有 6 个分片(3 个主分片和 3 个副本分片)的索引可以最大扩容到 6 个节点,每个节点上存在一个分片,并且每个分片拥有所在节点的全部资源。

更多的扩容——性能提升更多

  但是若我们想要扩容超过 6 个节点怎么办呢?

  主分片的数目在索引创建时就已经确定了下来。
  实际上,主分片数定义了这个索引能够 存储 的最大数据量(实际大小取决于你的数据、硬件和使用场景)。
  但是,读操作,即搜索和返回数据可以同时被主分片副本分片所处理。
  因此,当集群拥有的副本分片越多时,拥有的吞吐量也将越高。

  在运行中的集群上是可以动态调整副本分片数目的,因此可以按需伸缩集群。
  让我们把副本数从默认的 1 增加到 2

1
2
3
4
PUT /blogs/_settings
{
"number_of_replicas" : 2
}

  副本数修改后,集群变化后:

拥有 2 份副本分片的 3 个节点的集群

  现在, blogs 索引现在拥有 9 个分片:3 个主分片和 6 个副本分片。
  这意味着我们可以将集群扩容到 9 个节点,每个节点上一个分片。相比原来 3 个节点时,集群搜索性能可以提升 3 倍。

  当然,若只是在相同节点数目的集群上增加更多的副本分片并不能提高性能,因为每个分片从节点上获得的资源会变少。 你需要增加更多的硬件资源来提升吞吐量。

  但是更多的副本分片数提高了数据冗余量:按照上面的节点配置,我们可以在失去 2 个节点的情况下不丢失任何数据。

故障应对

  我们之前说过 Elasticsearch 集群可以应对节点故障,接下来让我们通过实验来验证下这个功能。
  若我们关闭第一个节点,这时集群将变为下图:

关闭了一个节点后的集群

  我们关闭的节点是一个主节点。而集群必须拥有一个主节点来保证正常工作,所以发生的第一件事情就是选举一个新的主节点: Node 2

  在我们关闭 Node 1 的同时也失去了主分片 12 ,并且在缺失主分片的时候索引也不能正常工作。
  因此,若此时来检查集群的状况,其的状态将会为 red :不是所有主分片都在正常工作。

  幸运的是,在其它节点上存在着这两个主分片的完整副本, 所以新的主节点立即将这些分片在 Node 2Node 3 上对应的副本分片提升为主分片, 此时集群的状态将会为 yellow
  注意哦:这个提升主分片的过程是瞬间发生的,如同按下一个开关一般。

  为什么我们集群状态是 yellow 而不是 green 呢?
  虽然我们拥有所有的三个主分片,但是同时设置了每个主分片需要对应 2 份副本分片,而此时只存在一份副本分片,所以集群不能为 green 的状态。
  不过我们不必过于担心:若我们同样关闭了 Node 2 ,我们的程序 依然 可以保持在不丢任何数据的情况下运行,因为 Node 3 为每一个分片都保留着一份副本。

  若我们重新启动 Node 1 ,集群可以将缺失的副本分片再次进行分配,那么集群的状态也将如水平扩容——更多的扩容所示图片。

  若 Node 1 依然拥有着之前的分片,它将尝试去重用它们,同时仅从主分片复制发生了修改的数据文件。

0%