elasticsearch(四)---分布式文档存储

在上一章,咱们看到了将数据放入索引而后检索它们的全部方法。不过咱们有意略过了许多关于数据是如何在集群中分布和获取的相关技术细节。这种使用和细节分离是刻意为之的——你不须要知道数据在Elasticsearch如何分布它就会很好的工做。html

这一章咱们深刻这些内部细节来帮助你更好的理解数据是如何在分布式系统中存储的。node

路由文档到分片

当你索引一个文档,它被存储在单独一个主分片上。Elasticsearch是如何知道文档属于哪一个分片的呢?当你建立一个新文档,它是如何知道是应该存储在分片1仍是分片2上的呢?算法

进程不能是随机的,由于咱们未来要检索文档。事实上,它根据一个简单的算法决定:安全

shard = hash(routing) % number_of_primary_shards
复制代码

routing值是一个任意字符串,它默认是_id但也能够自定义。这个routing字符串经过哈希函数生成一个数字,而后除以主切片的数量获得一个余数(remainder),余数的范围永远是0到number_of_primary_shards - 1,这个数字就是特定文档所在的分片。网络

这也解释了为何主分片的数量只能在建立索引时定义且不能修改:若是主分片的数量在将来改变了,全部先前的路由值就失效了,文档也就永远找不到了。异步

全部的文档API(get、index、delete、bulk、update、mget)都接收一个routing参数,它用来自定义文档到分片的映射。自定义路由值能够确保全部相关文档——例如属于同一我的的文档——被保存在同一分片上。async

主分片和复制分片如何交互

为了阐述意图,咱们假设有三个节点的集群。它包含一个叫作bblogs的索引并拥有两个主分片。每一个主分片有两个复制分片。相同的分片不会放在同一个节点上,因此咱们的集群是这样的:elasticsearch

咱们可以发送请求给集群中任意一个节点。每一个节点都有能力处理任意请求。每一个节点都知道任意文档所在的节点,因此也能够将请求转发到须要的节点。下面的例子中,咱们将发送全部请求给Node 1,这个节点咱们将会称之为请求节点(requesting node)分布式

当咱们发送请求,最好的作法是循环经过全部节点请求,这样能够平衡负载。
复制代码

新建索引和删除

新建、索引和删除请求都是写(write)操做,它们必须在主分片上成功完成才能复制到相关的复制分片上。函数

下面咱们罗列在主分片和复制分片上成功新建、索引或删除一个文档必要的顺序步骤:

1.客户端给Node 1发送新建、索引或删除请求。

2.节点使用文档的_id肯定文档属于分片0。它转发请求到Node 3,分片0位于这个节点上。

3.Node 3在主分片上执行请求,若是成功,它转发请求到相应的位于Node1和Node2的复制节点上。当全部的复制节点报告成功,Node3报告成功到请求的节点,请求的节点再报告给客户端。

客户端接收到成功响应的时候,文档的修改已经被应用于主分片和全部的复制分片。你的修改生效了。

有不少可选的请求参数容许你更改这一过程。你可能想牺牲一些安全来提升性能。这一选项不多使用由于Elasticsearch已经足够快,不过为了内容的完整咱们将作一些阐述。

replication

复制默认的值是sync。这将致使主分片获得复制分片的成功响应后才返回。

若是你设置replicationasync,请求在主分片上被执行后就会返回给客户端。它依旧会转发请求给复制节点,但你将不知道复制节点成功与否。

上面的这个选项不建议使用。默认的sync复制容许Elasticsearch强制反馈传输。async复制可能会由于在不等待其它分片就绪的状况下发送过多的请求而使Elasticsearch过载。

consistency

默认主分片在尝试写入时须要规定数量(quorum)或过半的分片(能够是主节点或复制节点)可用。这是防止数据被写入到错的网络分区。规定的数量计算公式以下:

int( (primary + number_of_replicas) / 2 ) + 1
复制代码

consistency容许的值为one(只有一个主分片),all(全部主分片和复制分片)或者默认的quorum或过半分片。

注意number_of_replicas是在索引中的的设置,用来定义复制分片的数量,而不是如今活动的复制节点的数量。若是你定义了索引有3个复制节点,那规定数量是:

int( (primary + 3 replicas) / 2 ) + 1 = 3
复制代码

但若是你只有2个节点,那你的活动分片不够规定数量,也就不能索引或删除任何文档。

timeout

当分片副本不足时会怎样?Elasticsearch会等待更多的分片出现。默认等待一分钟。若是须要,你能够设置timeout参数让它终止的更早:100表示100毫秒,30s表示30秒。

注意:
新索引默认有1个复制分片,这意味着为了知足quorum的要求须要两个活动的分片。固然,这个默认设置将阻止咱们在单一节点集群中进行操做。为了避开这个问题,规定数量只有在`number_of_replicas`大于一时才生效。
复制代码

检索文档

文档可以从主分片或任意一个复制分片被检索。

下面咱们罗列在主分片或复制分片上检索一个文档必要的顺序步骤:

1.客户端给Node 1发送get请求。

2.节点使用文档的_id肯定文档属于分片0。分片0对应的复制分片在三个节点上都有。此时,它转发请求到Node 2。

3.Node 2返回文档(document)给Node 1而后返回给客户端。

对于读请求,为了平衡负载,请求节点会为每一个请求选择不一样的分片——它会循环全部分片副本。

可能的状况是,一个被索引的文档已经存在于主分片上却还没来得及同步到复制分片上。这时复制分片会报告文档未找到,主分片会成功返回文档。一旦索引请求成功返回给用户,文档则在主分片和复制分片都是可用的。

局部更新文档

update API 结合了以前提到的读和写的模式。

下面咱们罗列执行局部更新必要的顺序步骤:

1.客户端给Node 1发送更新请求。

2.它转发请求到主分片所在节点Node 3。

3.Node 3从主分片检索出文档,修改_source字段的JSON,而后在主分片上重建索引。若是有其余进程修改了文档,它以retry_on_conflict设置的次数重复步骤3,都未成功则放弃。

4.若是Node 3成功更新文档,它同时转发文档的新版本到Node1和Node2上的复制节点以重建索引。当全部复制节点报告成功,Node3返回成功给请求节点,而后返回给客户端。

update API还接受《新建、索引和删除》章节提到的routingreplicationconsistencytimout参数。

基于文档的复制
当主分片转发更改给复制分片时,并非转发更新请求,而是转发整个文档的新版本。记住这些修改转发到复制节点是异步的,它们并不能保证到达的顺序与发送相同。若是Elasticsearch转发的仅仅是修改请求,修改的顺序多是错误的,那获得的就是个损坏的文档。
复制代码

多文档模式

mgetbulk API与单独的文档相似。差异是请求节点知道每一个文档所在的分片。它把多文档请求拆成每一个分片的对文档请求,而后转发每一个参与的节点。

一旦接收到每一个节点的应答,而后整理这些响应组合为一个单独的响应,最后返回给客户端。

下面咱们将罗列经过一个mget请求检索多个文档的顺序步骤:

1.客户端向Node 1发送mget请求。

2.Node 1为每一个分片构建一个多条数据检索请求,而后转发到这些请求所需的主分片或复制分片上。当全部回复被接收,Node 1构建响应并返回给客户端。

routing参数能够被docs中的每一个文档设置。

下面咱们将罗列使用一个bulk执行多个create、index、delete和update请求的顺序步骤:

1.客户端向Node 1发送bulk请求。

2.Node 1为每一个分片构建批量请求,而后转发到这些请求所需的主分片上。

3.主分片一个接一个的按序执行操做。当一个操做执行完,主分片转发新文档(或者删除部分)给对应的复制节点,而后执行下一个操做。一旦全部复制节点报告全部操做已成功完成,节点就报告success给请求节点,后者(请求节点)整理响应并返回给客户端。

bulk API还能够在最上层使用replicationconsistency参数,routing参数则在每一个请求的元数据中使用。

参考:elasticsearch权威指南

相关文章
相关标签/搜索