1.将文档路由到分片
索引文档时,它存储在单个主分片上。
Elasticsearch如何知道文档属于哪个分片?当我们创建一个新文档时,它是如何知道它是否应该将该文档存储在分片1或分片2上?
该过程不能是随机的,因为我们将来可能需要检索文档。事实上,它由一个简单的公式决定:
shard = hash(routing)%number_of_primary_shards
该routing
值是一个任意字符串,默认为文档 _id,
但也可以设置为自定义值。
此routing
字符串通过散列函数传递以生成一个数字,该数字除以索引中的主分片数以返回余数。其结果范围为[0,number_of_primary_shards - 1]
,结果的值正好和某个分片对应。
这解释了为什么主分片的数量 只有在创建索引并且永远不会更改时才能设置:如果将来更改主分片的数量,则所有先前的路由值都将无效,并且永远不会找到文档。
所有文件的API( get
,index
,delete
,bulk
,update
和mget
)都接受一个routing
参数可用于自定义文档到分片映射。
可以使用自定义路由值来确保所有相关文档(例如,属于同一用户的所有文档)存储在同一个分片上。
2.主分片和副本分片如何交互
出于解释目的,让我们来 想象一下,我们有一个由三个节点组成的集群。它包含一个名为的索引blogs
,它有两个主分片。每个主分片都有两个副本。
同一个分片的副本永远不会分配给同一个节点,因此我们的集群看起来像下图。
我们可以将请求发送到集群中的任何节点。 每个节点完全能够满足任何请求。
每个节点都知道集群中每个文档的位置,因此可以将请求直接转发到实际处理数据的节点。在后面的示例中,我们将发送所有请求Node 1
,我们将其称为协调节点(直接和客户端交互的节点)。
发送请求时,最好循环遍历群集中的所有节点,以便分散负载。
3.创建,索引和删除文档
创建,索引和删除 请求是写操作,必须在主分片上成功完成,然后才能将它们复制到任何关联的副本分片,如下图所示
下面是在主分片和任何副本分片上成功创建,索引或删除文档所需的主要步骤:
客户端发送创建,索引或删除请求给Node 1
。
节点使用文档_id
来确定文档属于分片0
。它将请求转发到主分片0所在的节点Node3上。
Node 3
在主分片上执行请求。如果是成功的,它并行转发请求给Node 1
和 Node 2
。一旦所有副本分片报告成功,Node 3
向协调节点(这里是Node0)报告成功,该协调节点向客户端报告成功。
当客户端收到成功响应时,已在主分片和所有副本分片上执行文档更改。修改是安全的。
有许多可选的请求参数允许您改变此过程,可能以数据安全性为代价提高性能。
这些选项很少使用,因为Elasticsearch已经很快了,但为了完整起见,这里解释了它们:
consistency
-
默认情况下,主分片需要法定数量或大部分的分片副本(其中分片副本可以是主分片或副本分片)在尝试写入操作之前可用。这是为了防止将数据写入网络分区的“错误方”(少数派)。法定人数定义如下:int((primary + number_of_replicas)/ 2)+ 1
允许的值
consistency
是one
(仅主要分片),all
(主要和所有副本),或默认quorum
或大多数分片副本。请注意,它
number_of_replicas
是索引设置中指定的副本数,而不是当前活动的副本数。如果您已指定索引应具有三个副本,则仲裁将如下所示:int((主要+3个复制品)/ 2)+ 1 = 3
但是,如果仅启动两个节点,则将没有足够的活动分片副本来满足仲裁,并且您将无法索引或删除任何文档。
timeout
- 如果可用的分片副本不足,会发生什么?Elasticsearch等待,希望会出现更多的分片。默认情况下,它将等待最多1分钟。如果需要,可以使用
timeout
参数让它更快地中止:100
是100毫秒,30s
是30秒。
默认情况下,新索引具有1个副本,这意味着应该需要两个活动分片副本以满足需要的quorum
。但是,这些默认设置会阻止我们对单节点群集执行任何有用的操作。为避免此问题,仅当number_of_replicas
大于1时才强制要求仲裁。
4.检索文档
可以从主分片或其任何副本分片检索文档,如下图所示。
以下是从主分片或副本分片检索文档的步骤:
客户端发送get请求Node 1
。
节点使用文档_id
来确定文档属于分片0
。所有三个节点上都存在分片0的副本。在这种情况下,它将请求转发给Node 2(此时理论上任何一个节点都可以处理)
。
Node 2
将文档返回到Node 1
,Node1将文档返回给客户端。
对于读取请求,协调节点将在每个请求上选择不同的分片副本以平衡负载; 它循环遍历所有分片副本。
在索引文档时,文档可能已经存在于主分片上但尚未复制到副本分片。在这种情况下,副本可能会报告文档不存在,而主副本可能会成功返回文档。索引请求将成功返回给用户后,该文档将在主分片和所有副本分片上可用。
5.文档部分更新
update
API结合了读和写模式,如下图所示:
以下是用于对文档执行部分更新的步骤序列:
- 客户端发送更新请求到
Node 1
。 - 它将请求转发到主分片所在的位置
Node 3
。 Node 3
从主分片中检索文档,更改_source
字段中的JSON ,并尝试在主分片上重新索引文档。如果文档已被其他进程更改,则会在放弃之前重试第3步retry_on_conflict次
。- 如果
Node 3
已成功更新文档,则会将要重新编制索引的新版本的文档并行转发到副本分片Node 1
和Node 2
。所有副本分片报告成功后,Node 3
向协调节点报告成功,协调节点向客户端报告成功。
该update
API也接受了routing
,consistency
和 timeout
那些参数
当主分片转发到其副本分片时, 它不转发更新请求。相反,它转发整个文档的新版本。
请记住,这些更改会异步转发到副本分片,并且无法保证它们的到达顺序与它们的发送顺序相同。
如果Elasticsearch仅转发更改,则可能会以错误的顺序应用更改,从而导致文档损坏。
6.多文档模式
mget
和bulk
API 的模式 与个别文件类似。不同之处在于协调节点知道每个文档存在于哪个分片中。它将多文档请求分解为每个分片的多文档请求,并将这些请求并行转发到每个参与节点。
一旦它从每个节点收到答复,它就会将他们的响应整理成一个响应,并将其返回给客户端,如下图所示:
以下是使用单个mget
请求检索多个文档所需的步骤序列:
- 客户端发送
mget
请求Node 1
。 Node 1
为每个分片构建一个多重获取请求,并将这些请求并行转发到存在对应主分片或者副本分片的节点。收到所有回复后,Node 1
构建响应并将其返回给客户端。
一个routing
参数可以为docs
数组中的每个文档设置。
批量API,如图13“多文档更改bulk
”所示,允许在单个批量请求中执行多个创建,索引,删除和更新请求。
图13.使用的多个文档更改 bulk
步骤顺序 其次是 bulk
API如下:
- 客户端发送
bulk
请求Node 1
。 Node 1
为每个分片构建批量请求,并将这些请求并行转发到托管每个涉及的主分片的节点。- 主分片一个接一个地连续执行每个动作。当每个操作成功时,主服务器将新文档(或删除)并行转发到其副本分片,然后继续执行下一个操作。一旦所有副本分片报告所有操作成功,该节点就会向协调节点报告成功,协调节点整理响应并将它们返回给客户端。
该bulk
API也接受整个bulk
请求指定consistency,并且每个子请求指定routing
参数。
为什么是这样奇怪的格式?
当我们了解批量请求时,您可能会问自己,“为什么bulk
API需要使用换行符的有趣格式,而不是仅仅发送包含在JSON数组中的请求,比如mget
API?”
为了回答这个问题,我们需要解释一些背景:批量请求中引用的每个文档可能属于不同的主分片,每个分片都可以分配给集群中的任何节点。这意味着每个内部bulk
请求需要被转发到正确的分片正确的节点上。
如果各个请求都包含在JSON数组中,那么这意味着我们需要执行以下操作:
- 将JSON解析为数组(包括文档数据,可能非常大)
- 查看每个请求以确定它应该转到哪个分片
- 为每个分片创建一组请求
- 将这些数组序列化为内部传输格式
- 将请求发送到每个分片
它可以工作,但需要大量的RAM来保存基本上相同数据的副本,并且会创建更多的数据结构,Java虚拟机(JVM)必须花费时间进行垃圾收集。
相反,Elasticsearch进入网络缓冲区,在那里收到原始请求,并直接读取数据。它使用换行符来识别和解析小的action/metadata请求
,以便决定哪个分片应该处理每个请求。
这些原始请求将直接转发到正确的分片。没有冗余的数据复制,没有浪费的数据结构。整个请求过程在尽可能少的内存中处理。
原文地址:https://www.cnblogs.com/gc65/p/10647959.html