ElasticSearch——详细介绍集群节点定义、索引与分片的关系,以及分片与副本

参考:ElasticSearch——详细介绍集群节点定义、索引与分片的关系,以及分片与副本

集群

一个运行中的 Elasticsearch 实例称为一个节点,而集群是由一个或者多个拥有相同 cluster.name 配置的节点组成, 它们共同承担数据和负载的压力。当有节点加入集群中或者从集群中移除节点时,集群将会重新平均分布所有的数据。

主节点

主节点负责集群层面的相关操作,管理集群变更。通过配置 node.master: true(默认)使节点具有被选举为Master 的资格。主节点是全局唯一的,将从有资格成为Master的节点中进行选举。

主节点也可以作为数据节点,但尽可能做少量的工作,因此生产环境应尽量分离主节点和数据节点,创建独立主节点的配置:

node.master: true
node.data: false

为了防止数据丢失,每个主节点应该知道有资格成为主节点的数量,默认为1,为避免网络分区时出现多主的情况,配置discovery.zen.minimum_master_nodes原则上最小值应该是:

(master_eligible_nodes / 2) + 1

当一个节点被选举成为主节点时, 它将负责管理集群范围内的所有变更,例如增加、删除索引,或者增加、删除节点等
而主节点并不需要涉及到文档级别的变更和搜索等操作所以当集群只拥有一个主节点的情况下,即使流量的增加它也不会成为瓶颈。 任何节点都可以成为主节点。我们的示例集群就只有一个节点,所以它同时也成为了主节点。

数据节点

负责保存数据、执行数据相关操作:CRUD、搜索、聚合等。数据节点对CPU、内存、I/O要求较高。
一般情况下(有一些例外)数据读写流程只和数据节点交互,不会和主节点打交道(异常情况除外)

通过配置node.data: true(默认)来使一个节点成为数据节点,也可以通过下面的配置创建一个数据节点:

node.master: false
node.data: true
node.ingest: false

预处理节点(Ingest Node)

这是从5.0版本开始引入的概念。预处理操作允许在索引文档之前,即写入数据之前,通过事先定义好的一系列的processors(处理器)和pipeline(管道),对数据进行某种转换、富化。
processors和pipeline拦截bulk和index请求,在应用相关操作后将文档传回给index或bulk API。

默认情况下,在所有的节点上启用ingest,如果想在某个节点上禁用ingest,则可以添加配置node.ingest: false,也可以通过下面的配置创建一个仅用于预处理的节点:

node.master: false
node.data: false
node.ingest: true

协调节点(Coordinating node)

作为用户,可以将请求发送到集群中的任何节点(包括主节点)。 每个节点都知道任意文档所处的位置,并且能够将我们的请求直接转发到存储我们所需文档的节点。 无论我们将请求发送到哪个节点,它都能负责从各个包含我们所需文档的节点收集回数据,并将最终结果返回给客户端。处理客户端请求的节点称为协调节点

协调节点将请求转发给保存数据的数据节点。每个数据节点在本地执行请求,并将结果返回协调节点。协调节点收集完数据后,将每个数据节点的结果合并为单个全局结果。对结果收集和排序的过程可能需要很多CPU和内存资源。通过下面的配置创建一个仅用于协调的节点:

node.master: false
node.data: false
node.ingest: false

部落节点(Tribe node)

tribes(部落)功能允许部落节点在多个集群之间充当联合客户端。
在ES 5.0之前还有一个客户端节点(Node Client)的角色,客户端节点有以下属性:

node.master: false
node.data: false

它不做主节点,也不做数据节点,仅用于路由请求本质上是一个智能负载均衡器(从负载均衡器的定义来说,智能和非智能的区别在于是否知道访问的内容存在于哪个节点),从5.0版本开始,这个角色被协调节点(Coordinating only node)取代。

集群健康度

Elasticsearch 的集群监控信息中包含了许多的统计数据,其中最为重要的一项就是** 集群健康** , 它在 status 字段中展示为 green 、 yellow 或者 red。使用下面的命令查看集群健康度:

GET /_cluster/health?pretty

返回值可能为:

{
   "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 字段是我们关心的,它表示当前集群在总体上的工作状态。它的三种颜色含义如下:

  • green

所有****主分片和副本分片都正常运行

  • yellow

所有主分片都正常运行,但不是所有的副本分片都正常运行

  • red

有(部分或全部)主分片未能正常运行

索引的添加

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

索引与分片的比较

**一个 Lucene 索引我们在 Elasticsearch称作分片 **。 一个 Elasticsearch 索引 是分片的集合
当 Elasticsearch 在索引中搜索的时候, 他发送查询到每一个属于索引的分片(Lucene 索引),然后像执行分布式检索 提到的那样,合并每个分片的结果到一个全局的结果集。

分片

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

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

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

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

副本分配可以提供读操作。一个副本分片只是一个主分片的拷贝。副本分片作为硬件故障时保护数据不丢失的冗余备份,并为搜索和返回文档等读操作提供服务。
在索引建立的时候就已经确定了主分片数,但是副本分片数可以随时修改

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

PUT /blogs
{
   "settings" : {
      "number_of_shards" : 3,
      "number_of_replicas" : 1
   }
}

目前集群是“拥有一个索引的单节点集群”。所有3个主分片都被分配在 Node 1 ,如下图所示:
ElasticSearch——详细介绍集群节点定义、索引与分片的关系,以及分片与副本_第1张图片
查看集群状态:

GET /_cluster/health?pretty

得到结果如下:

{
  "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:集群 status 值为 yellow :表名主分片都正常运行,但是副本分片没有全部处于正常状态
  • unassigned_shards:没有被分配到任何节点的副本数。在同一个节点上既保存原始数据又保存副本是没有意义的,因为一旦失去了那个节点,我们也将丢失该节点上的所有副本数据

故障转移

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

如果启动了第二个节点,拥有两个节点的集群最终所有主分片和副本分片都将被分配。其状态如下所示:
ElasticSearch——详细介绍集群节点定义、索引与分片的关系,以及分片与副本_第2张图片
当第二个节点加入到集群后,3个副本分片将会分配到这个节点上——每个主分片对应一个副本分片。 这意味着当集群内任何一个节点出现问题时,我们的数据都完好无损。

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

cluster-health 现在展示的状态为 green ,这表示所有6个分片(包括3个主分片和3个副本分片)都在正常运行

{
  "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
}

如何定位文档所在分片

当索引(这里是动词)一个文档的时候,文档会被存储到一个主分片中

Elasticsearch 如何知道一个文档应该存放到哪个分片中呢?当我们创建文档时,它如何决定这个文档应当被存储在分片 1 还是分片 2 中呢?
这个过程是根据下面这个公式决定的:

shard = hash(routing) % number_of_primary_shards

**routing 是一个可变值,默认是文档的 _id **,也可以设置成一个自定义的值。 routing 通过 hash 函数生成一个数字,然后这个数字再除以 number_of_primary_shards (主分片的数量)后得到余数 。这个分布在 0 到 number_of_primary_shards-1 之间的余数,就是我们所寻求的文档所在分片的位置。

这就解释了为什么我们要在创建索引的时候就确定好主分片的数量 并且永远不会改变这个数量:因为如果数量变化了,那么所有之前路由的值都会无效,文档也再也找不到了。

你可能觉得由于 Elasticsearch 主分片数量是固定的会使索引难以进行扩容。实际上当你需要时有很多技巧可以轻松实现扩容。在后续会详细讨论扩容设计。

所有的文档 API( get 、 index 、 delete 、 bulk 、 update 以及 mget )都接受一个叫做** routing 的路由参数** ,通过这个参数我们可以自定义文档到分片的映射。一个自定义的路由参数可以用来确保所有相关的文档——例如所有属于同一个用户的文档——都被存储到同一个分片中。

主分片和副本分片的交互

为了说明目的,假设有一个集群由三个节点组成。 它包含一个叫 blogs 的索引,有两个主分片,每个主分片有两个副本分片相同分片的副本不会放在同一节点,所以我们的集群看起来像下图所示:
ElasticSearch——详细介绍集群节点定义、索引与分片的关系,以及分片与副本_第3张图片
我们可以发送请求到集群中的任一节点。 每个节点都有能力处理任意请求
每个节点都知道集群中任一文档位置,所以可以直接将请求转发到需要的节点上

当发送请求的时候, 为了扩展负载,更好的做法是轮询集群中所有的节点。

你可能感兴趣的:(读书笔记,elasticsearch,大数据,java)