1. 路由文档到分片
1.1 文档路由规则
ES是如何知道将当前文档存储到哪个分片上的呢?有一个简单的算法
shard = hash(routing) % number_of_primary_shards
routing默认为_id
这也就解释了为什么主分片数量在创建索引时必须定义且不能改变,如果主分片的数量改变,那么之前的路由算法就会作废,使得文档检索不到。
但是也不用认为这就失去了拓展性,存在相应的扩展技术使得扩展变得容易
1.2 主 复制分片之间如何交互
助理解的术语:
请求结点:请求到达的第一个结点
1.2.1 索引、更新与删除文档
索引、更新与删除文档都是写操作,写操作必须在主分片上完成时,才能复制到复制分片上。
下面我们罗列一下必要的步骤:
1. 客户端给NODE1发送索引、更新与删除的请求
2. 结点1根据”_id”和索引算法判断该文档属于0分片。将请求转发至NODE3
3. NODE3 在主分片上执行操作,如果操作成功,转发请求至NODE1 和 NODE2上的复制分片。当所有的复制分片执行成功后,NODE3 报告执行成功到NODE1,NODE1在报告给客户端。
当客户端接收到成功报告时,所有更改文档的请求早已在所有的分片上执行完毕。
1.2.2 一些配置
replication
默认情况下,当所有的复制结点执行成功时,请求结点才会给客户端返回成功执行的信息。可以通过设置replication(应答),来决定在主分片执行成功后就返回执行成功响应,还是在主分片复制分片全部执行成功后才返回。
默认值:sync
可更改值:async
consistency 不是很理解
timeout
当复制分片不够时,ES默认会等待一分钟等待新的复制分片出现,你可以缩短它的时间,30->30毫秒,30s->30秒
2. 检索文档
1. 客户端请求到NODE1
2. 根据文档id和索引算法,算出文档在0分片上。
3. 将请求转发到NODE2上
4. NODE2返回文档给NODE1,然后NODE1返回给客户端
问题:为什么不直接在NODE1上的R0索引数据?
回答:为了对请求负载均衡,使请求的压力均摊到各个结点上。
不光这样,每次请求还会轮训同一组分片,0 1 2 3。。0这样子轮训,也是为了平衡负载
一些特殊情况
一个索引的文档刚索引到主分片上,还没来得及复制到复制分片上。此时就有一个请求,检索该文档。那么此时复制分片上返回的结果是没有索引到,但是主分片会将此文档返回给请求结点,请求结点再返回给客户端。
3. 局部更新文档
- 客户端请求到NODE1
- 根据id和索引算法,得知文档在0分片上,转发请求到0分片主分片所在的NODE3上
- 在NODE3上检索出文档,修改_source字段的JSON,然后重建索引(文档一旦建立是不允许修改的,所以当更新为文档的时候,会先将旧文档删除,然后添加上新文档)。如果有其他进程在检索期间修改了文档,则按照retry_on_conflict设置的次数进行重试,如果重试次数内都未成功,则放弃。
- 从0分片的主分片上,转发 最新版本(不是请求) 到各个复制分片。当所有的复制分片返回成功后,NODE3返回成功给NODE1,NODE1返回成功给客户端。
为什么传递最新版本,因为基于_version的更改是安全的。但是基于请求的话,不一定是安全的,很可能导致文档受损。
4. 多文档模式
mget命令
多文档检索步骤:
1. 客户端发送多文档请求命令到一个结点上
2. 该结点根据请求,为每组分片建立一个多条数据检索的请求,然后转发到该组分片所在的结点上(主复制随机),等待这些结点将响应结果返回到请求结点。请求结点再将响应结果进行构建,返回给客户端。
bulk命令
多文档操作步骤:
1. 客户端发送请求到请求结点上
2. 请求结点根据请求,为每个主分片(因为是写请求)构建批量操作请求,转发到响应的主分片所在的结点
3. 主分片更新完成后,将文档的最新版本转发到各个复制分片对应的结点上。收集所有复制分片的成功回复,然后回复给请求结点
4. 请求结点收集所有主分片所在结点的成功回复后,返回给客户端