zl程序教程

您现在的位置是:首页 >  工具

当前栏目

【ES三周年】04-ElasticSearch进阶

ESelasticsearch 进阶 04 三周年
2023-06-13 09:18:26 时间

4.1 分布式集群

4.1.1 单节点集群

我们在包含一个节点的集群中创建名为users的索引,为了演示目的,我们将为该索引分配3个主分片和一个副本(每个主分片拥有一个副本分片):

postman 发起PUT请求:http://127.0.0.1:9200/users

请求体:

{
    "settings":{
        "number_of_shards":3,
        "number_of_replicas":1
    }
}

查询该索引:

postman 发起GET请求:http://127.0.0.1:9200/users

响应:

{
    "users": {
        "aliases": {},
        "mappings": {},
        "settings": {
            "index": {
                "routing": {
                    "allocation": {
                        "include": {
                            "_tier_preference": "data_content"
                        }
                    }
                },
                "number_of_shards": "3", // 主分片为3
                "provided_name": "users",
                "creation_date": "1648041297821",
                "number_of_replicas": "1", // 副本为1
                "uuid": "-zdttGQ8TK6IS-kBVQAALw",
                "version": {
                    "created": "7150299"
                }
            }
        }
    }
}

此时我们的集群是一个拥有索引的单节点集群,所有3个主分片都被分配在了当前启动的es节点下。

通过elasticsearch-head(google插件)查看集群状况:

  • 当前集群的全部主分片都正常运行,但是副本分片没有全部处在正常状态

三个主分片正常。

3个副本分片都是Unassigned——他们都没被分配到任何节点。在同一个节点上既保存原始数据,有保存副本是没有意义的,因为一旦失去了那个节点,我们也就丢失了该节点的所有副本数据。

  • 如此显示说明:当前我们的集群是正常运行的 ,但是在硬件故障的时候有丢失数据的风险。

4.1.2 故障转移

当集群中只有一个节点在运行时,意味着会有一个单点故障问题——没有冗余。

幸运的是,我们只需再启动一个节点即可防止数据丢失。当你在同一台机器上启动了第二个节点时,只要它和第一个节点有同样的cluster.name配置,它就会自动发现集群并加入到其中。

但是在不同机器上启动节点的时候,为了加入到同一集群,你需要配置一个可连接到的单播主机列表。之所以配置为使用单播发现,以防止节点无意中加入集群。只有在同一台机器上运行的节点才会自动组成集群。

启动node-8002节点(windows集群那部分已经弄好的)

如果启动了第二个节点,我们的集群将会拥有两个节点的集群:所有主分片和副本分片都已被分配。

可以看到★就是master节点,加粗的就是主分片,细的就是副本

当第二个节点加入到集群中后,3个副本分片将会自动分配到这个节点上——每个主分片对应一个副本分片。这意味着当集群内任何一个节点出现问题时,我们的数据都完好无损。所有新近被索引的文档都将会保存在主分片上,然后被并行的复制到对应的副本分片上。这就保证了我们既可以从主分片又可以从副本分片上获得文档。

4.1.3 水平扩容

怎样为我们正在增长的应用程序按需扩容呢?当启动了第三个节点node-8003,我们的集群将会拥有三个节点的集群:为了分散负载而对分片重新分配。

启动node-8003节点,等待一会刷新页面:

node-8001、node-8002上各有一个分片被迁移到了新的node-8003节点上,现在每个节点上都拥有2个分片,而不是之前的三个。这表示每个节点的硬件资源(CPU.RAM.I/O)将被更少的分片所共享,每个分片的性能将会得到提升。

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

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

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

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

postman发起PUT请求:http://localhost:8001/users/_settings

请求体:

{
    "number_of_replicas":2
}

刷新:

4.1.4 应对故障

如果某个时刻,一个节点突然断掉,会发送什么:

比如我们把node-8001关闭

可以看到,我们的主节点master还在,但是因为node-8001关闭了,它上面的副本就无法使用了,所以集群健康值就变成了黄色,但是仍然可以正常提供服务,只是性能可能会变差一点,

如果此时我们把node-8001启动会怎样:

要修改配置文件:

# 他要找到node-8002、和node-8003
discovery.seed_hosts: ["localhost:9302", "localhost:9302"]

如果找到的话,node-8001节点就会恢复,可以发现唯一的变化就是master节点发生了变化

4.1.5 路由计算 & 分片控制

路由计算:hash(id)%主分片数量

4.1.6 数据写流程

新建、索引和删除请求都是写操作, 必须在主分片上面完成之后才能被复制到相关的副本分片。

  1. 客户端请求集群节点(任意),——协调节点。
  2. 协调节点将请求转换到指定的节点。
  3. 主分片需要将数据保存。
  4. 主分片 发送数据给副本
  5. 副本保存后,进行反馈。
  6. 主分片进行反馈
  7. 客户端获取反馈

在客户端收到成功响应时,文档变更已经在主分片和所有副本分片执行完成,变更是安全的。

有一些可选的请求参数允许您影响这个过程,可能以数据安全为代价提升性能。这些选项很少使用,因为 Elasticsearch 已经很快,但是为了完整起见, 请参考下文:

参数

说明

consistency

即一致性。在默认设置下,即使仅仅是在试图执行一个写操作之前,主分片都会要求必须要有规定数量quorum(或者换种说法,也即必须要有大多数)的分片副本处于活跃可用状态,才会去执行写操作(其中分片副本 可以是主分片或者副本分片)。这是为了避免在发生网络分区故障(network partition)的时候进行写操作,进而导致数据不一致。 规定数量即: int((primary + number_of_replicas) / 2 ) + 1 consistency 参数的值可以设为: + one :只要主分片状态 ok 就允许执行写操作。 + all:必须要主分片和所有副本分片的状态没问题才允许执行写操作。 + quorum:默认值为quorum , 即大多数的分片副本状态没问题就允许执行写操作。 注意,规定数量的计算公式中number_of_replicas指的是在索引设置中的设定副本分片数,而不是指当前处理活动状态的副本分片数。如果你的索引设置中指定了当前索引拥有3个副本分片,那规定数量的计算结果即:int((1 primary + 3 replicas) / 2) + 1 = 3,如果此时你只启动两个节点,那么处于活跃状态的分片副本数量就达不到规定数量,也因此您将无法索引和删除任何文档。

timeout

如果没有足够的副本分片会发生什么? Elasticsearch 会等待,希望更多的分片出现。默认情况下,它最多等待 1 分钟。 如果你需要,你可以使用timeout参数使它更早终止:100是100 毫秒,30s是30秒。 新索引默认有1个副本分片,这意味着为满足规定数量应该需要两个活动的分片副本。 但是,这些默认的设置会阻止我们在单一节点上做任何事情。 为了避免这个问题,要求只有当number_of_replicas 大于1的时候,规定数量才会执行。

4.1.7 数据读操作

部分更新一个文档结合了先前说明的读取和写入流程:

  1. 客户端请求集群节点(任意),——协调节点。
  2. 协调节点计算数据所在分片,以及全部副本位置。
  3. 为了负载均衡,可以轮询所有节点。
  4. 将请求转发给具体的那个节点。
  5. 节点返回查询结果,将反馈结果给客户端。

在处理读取请求时,协调结点在每次请求的时候都会通过轮询所有的副本分片来达到负载均衡。

在文档被检索时,已经被索引的文档可能已经存在于主分片上但是还没有复制到副本分片。 在这种情况下,副本分片可能会报告文档不存在,但是主分片可能成功返回文档。 一旦索引请求成功返回给用户,文档在主分片和副本分片都是可用的。

4.1.8 更新流程

部分更新一个文档的步骤如下:

  1. 客户端向Node 1发送更新请求。
  2. 它将请求转发到主分片所在的Node 3 。
  3. Node 3从主分片检索文档,修改_source字段中的JSON,并且尝试重新索引主分片的文档。如果文档已经被另一个进程修改,它会重试步骤3 ,超过retry_on_conflict次后放弃。
  4. 如果 Node 3成功地更新文档,它将新版本的文档并行转发到Node 1和 Node 2上的副本分片,重新建立索引。一旦所有副本分片都返回成功,Node 3向协调节点也返回成功,协调节点向客户端返回成功。

4.1.9 多文档操作流程

mget和bulk API的模式类似于单文档模式。区别在于协调节点知道每个文档存在于哪个分片中。它将整个多文档请求分解成每个分片的多文档请求,并且将这些请求并行转发到每个参与节点。

协调节点一旦收到来自每个节点的应答,就将每个节点的响应收集整理成单个响应,返回给客户端。

用单个 mget 请求取回多个文档所需的步骤顺序:

  1. 客户端向 Node 1 发送 mget 请求。
  2. Node 1为每个分片构建多文档获取请求,然后并行转发这些请求到托管在每个所需的主分片或者副本分片的节点上。一旦收到所有答复,Node 1 构建响应并将其返回给客户端。

可以对docs数组中每个文档设置routing参数。

bulk API, 允许在单个批量请求中执行多个创建、索引、删除和更新请求。

bulk API 按如下步骤顺序执行:

  1. 客户端向Node 1 发送 bulk请求。
  2. Node 1为每个节点创建一个批量请求,并将这些请求并行转发到每个包含主分片的节点主机。
  3. 主分片一个接一个按顺序执行每个操作。当每个操作成功时,主分片并行转发新文档(或删除)到副本分片,然后执行下一个操作。一旦所有的副本分片报告所有操作成功,该节点将向协调节点报告成功,协调节点将这些响应收集整理并返回给客户端。

4.1.10 倒排索引

Elasticsearch使用一种称为倒排索引的结构,它适用于快速的全文搜索。

见其名,知其意,有倒排索引,肯定会对应有正向索引。正向索引(forward index),反向索引(inverted index)更熟悉的名字是倒排索引