分布式增删改查
3.1 路由文档到分片
路由算法:
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参数,它用来自定义文档到分片的映射。
3.2 主分片和复制分片如何交互
它包含一个叫做bblogs的索引并拥有两个主分片。每个主分片有两个复制分片。相同的分片不会放在同一个节点上,所以我们的集群是这样的:
我们能够发送请求给集群中任意一个节点。每个节点都有能力处理任意请求。每个节点都知道任意文档所在的节点,所以也可以将请求转发到需要的节点。下面的例子中,我们将发送所有请求给Node 1,这个节点我们将会称之为请求节点(requesting node)
3.3 新建、索引和删除文档
新建、索引和删除请求都是写(write)操作,它们必须在主分片上成功完成才能复制到相关的复制分片上。
下面我们罗列在主分片和复制分片上成功新建、索引或删除一个文档必要的顺序步骤:
- 1.客户端给Node 1发送新建、索引或删除请求。
- 2.节点使用文档的_id确定文档属于分片0。它转发请求到Node 3,分片0位于这个节点上。
- 3.Node 3在主分片上执行请求,如果成功,它转发请求到相应的位于Node 1和Node 2的复制节点上。当所有的复制节点报告成功,Node 3报告成功到请求的节点,请求的节点再报告给客户端。
replication
复制默认的值是sync。这将导致主分片得到复制分片的成功响应后才返回。
如果你设置replication为async,请求在主分片上被执行后就会返回给客户端。它依旧会转发请求给复制节点,但你将不知道复制节点成功与否。
consistency
默认主分片在尝试写入时需要规定数量(quorum)或过半的分片可用。这是防止数据被写入到错的网络分区,公式如下:
int( (primary + number_of_replicas) / 2 ) + 1
3.4 检索文档
文档能够从主分片或任意一个复制分片被检索。
下面我们罗列在主分片或复制分片上检索一个文档必要的顺序步骤:
- 1.客户端给Node 1发送get请求。
- 2.节点使用文档的_id确定文档属于分片0。分片0对应的复制分片在三个节点上都有。此时,它转发请求到Node 2。
- 3.Node 2返回文档(document)给Node 1然后返回给客户端。
对于读请求,为了平衡负载,请求节点会为每个请求选择不同的分片——它会循环所有分片副本。
3.5 局部更新文档
update API 结合了之前提到的读和写的模式。 下面我们罗列执行局部更新必要的顺序步骤:
- 1.客户端给Node 1发送更新请求。
- 2.它转发请求到主分片所在节点Node
- 3.Node 3从主分片检索出文档,修改_source字段的JSON,然后在主分片上重建索引。如果有其他进程修改了文档,它以retry_on_conflict设置的次数重复步骤3,都未成功则放弃。
- 4.如果Node 3成功更新文档,它同时转发文档的新版本到Node 1和Node 2上的复制节点以重建索引。当所有复制节点报告成功,Node 3返回成功给请求节点,然后返回给客户端。
3.6 多文档模式
mget和bulk API与单独的文档类似。差别是请求节点知道每个文档所在的分片。它把多文档请求拆成每个分片的对文档请求,然后转发每个参与的节点。
一旦接收到每个节点的应答,然后整理这些响应组合为一个单独的响应,最后返回给客户端。 下面我们将罗列通过一个mget请求检索多个文档的顺序步骤:
- 1.客户端向Node 1发送mget请求。
- 2.Node 1为每个分片构建一个多条数据检索请求,然后转发到这些请求所需的主分片或复制分片上。当所有回复被接收,Node 1构建响应并返回给客户端。
下面我们将罗列使用一个bulk执行多个create、index、delete和update请求的顺序步骤:
- 1.客户端向Node 1发送bulk请求。
- 2.Node 1为每个分片构建批量请求,然后转发到这些请求所需的主分片上。
- 3.主分片一个接一个的按序执行操作。当一个操作执行完,主分片转发新文档(或者删除部分)给对应的复制节点,然后执行下一个操作。一旦所有复制节点报告所有操作已成功完成,节点就报告success给请求节点,后者(请求节点)整理响应并返回给客户端。