[ElasticSearch]分布式文档存储(Distributed Document Store)

来源:互联网 发布:阿里云系统看电视 编辑:程序博客网 时间:2024/05/21 14:09

之前的文章中,我们已经知道如何存储数据到索引中以及如何检索它。但是我们掩盖了数据存储到集群中以及从集群中获取数据的具体实现的技术细节(But we glossed over many technical details surrounding how the data is distributed and fetched from the cluster)。

1. 路由文档到分片中(Routing a Document to a Shard)

当你索引一篇文档时,它会存储到一个主分片中。但是ElasticSearch如何知道文档是属于哪个分片呢?当我们创建一个新的文档,它是怎么知道它是应该存储到分片1上还是分片2上?

数据存储到分片的过程是一定规则的,并不是随机发生的,因为我们日后还需要从分片中检索出文档。数据存储过程取决于下面的公式:

  1. shard = hash(routing) % number_of_primary_shards

Routing值是一个任意字符串,默认为文档的id,也可以设置为一个用户自定义的值。Routing这个字符串通过一个hash函数处理,并返回一个数值,然后再除以索引中主分片的数目,所得的余数作为主分片的编号,取值一般在0到number_of_primary_shards - 1的这个范围中。通过这种方法计算出该数据是存储到哪个分片中。

这就解释了为什么主分片个数当创建索引之后就不能再更改了:如果主分片个数在创建之后可以修改,那么之前所有通过公式得到的值都会失效,之前存储的文档也可能找不到。

所有的文档API(get , index , delete , bulk , update , 和 mget)都可以接受一个routing参数,来自定义文档与分片之间的映射。

2. 主分片与副本分片如何交互

假设我们有一个三个节点的集群。集群里有一个名称为"blog"的索引,有两个主分片(primary shards)。每个主分片都有两个副本。相同节点的拷贝不会分配到同一节点,最后如下图展示:

我们可以发送请求到集群中的任何一个节点,每个节点都有能力处理我们的请求。每个节点都知道集群中每篇文档的存储位置,所以可以直接请求转发到所需的节点(Every node knows the location of every document in the cluster,so can forward requests directly to the required node)。

在下面的例子中,我们发送请求都发到节点1上。

2.1 创建,索引和删除文档(Creating, Indexing, and Deleting a Document)

创建,索引和删除请求都是写操作,所以在复制到相关副本分片之前一定成功的写到主分片上(Create, index, and delete requests are write operations, which must be successfully completed on the primary shard before they can be copied to any associated replica shards)。交互过程如下图所示:

下面是成功在主分片和副本分片上创建,索引以及删除文档所必须的步骤:

(1)客户端发送了一个Create,Index 或者 Delete 请求给节点 1(节点1为请求节点);

(2)节点 1 通过请求文档的 id 值判断出该文档应该被存储在分片 0 中,并且知道分片 0  的主分片 P0 位于节点 3 上。因此节点 1 会把这个请求转发给节点 3;

(3)节点 3 在主分片上执行请求。如果请求执行成功,节点 3 并行将该请求转发给节点 1 和节点 2 上的的副本分片(R0)。一旦所有的副本分片都成功地执行了请求,则向节点 3 报告成功,节点 3 向请求节点 (Node 1 )报告成功,请求节点向客户端报告成功。

2.2 检索一个文档(Retrieving a Document)

我们可以从一个主分片(primary shard)或者它们任一副本中检索一篇文档,流程如下图:

下面是从主分片或者副本分片上检索一篇文档所需要的一系列步骤:

(1)客户端发送了一个 Get 请求给节点 1(请求节点);

(2)节点 1 通过请求文档的 id 值判断出该文档被存储在分片 0 中。三个节点上都存有分片 0 的复制(节点1上R0,节点2上R0,节点3上P0)(Copies of shard 0 exist on all three nodes)。这一次,它将请求转发给节点 2 。

(3)节点 2 返回文档给节点 1 ,节点 1 在返回文档给客户端。

对于读请求,对于每一次请求,请求节点都会选择一个不同的节点(shard copy),达到负载均衡。它会循环请求所有的节点(shard copy)。

2.3 局部更新一个文档(Partial Updates to a Document)

更新 API (Update API)融合了上面解释的两种读写模式,如下图所示:

下面是部分更新一篇文档所需要的一系列步骤:

(1)客户端发送了一个 Update 请求给节点 1(请求节点);

(2)节点 1 通过请求文档的 id 值判断出该文档被存储在分片 0 中。并且知道分片 0  的主分片 P0 位于节点 3 上。因此节点 1 会把这个请求转发给节点 3;

(3)节点 3 从主分片(P0)上检索出指定文档,并更改_source字段中的JSON,修改完毕之后试着重新索引文档到主分片(P0)上。如果有人已经修改了该文档,那么会重复步骤3,如果尝试retry_on_conflict次还没有成功则放弃。

(4)如果节点 3 更新文档成功,节点 3 会把文档新版本并行发给节点 1 和 节点 2 上的副本分片,重新索引文档。一旦所有的副本分片报告成功,节点 3 向请求节点报告成功,请求节点向客户端报告成功。




1 0
原创粉丝点击