elasticsearch的查询流程分析

咱们都知道es是一个分布式的存储和检索系统,在存储的时候默认是根据每条记录的_id字段作路由分发的,这意味着es服务端是准确知道每一个document分布在那个shard上的。node

相对比于CURD上操做,search一个比较复杂的执行模式,由于咱们不知道那些document会被匹配到,任何一个shard上都有可能,因此一个search请求必须查询一个索引或多个索引里面的全部shard才能完整的查询到咱们想要的结果。并发

找到全部匹配的结果是查询的第一步,来自多个shard上的数据集在分页返回到客户端的以前会被合并到一个排序后的list列表,因为须要通过一步取top N的操做,因此search须要进过两个阶段才能完成,分别是query和fetch。负载均衡

(一)query(查询阶段)分布式

当一个search请求发出的时候,这个query会被广播到索引里面的每个shard(主shard或副本shard),每一个shard会在本地执行查询请求后会生成一个命中文档的优先级队列。性能

这个队列是一个排序好的top N数据的列表,它的size等于from+size的和,也就是说若是你的from是10,size是10,那么这个队列的size就是20,因此这也是为何深度分页不能用from+size这种方式,由于from越大,性能就越低。fetch

es里面分布式search的查询流程以下:code

image

1,客户端发送一个search请求到Node 3上,而后Node 3会建立一个优先级队列它的大小=from+size

2,接着Node 3转发这个search请求到索引里面每个主shard或者副本shard上,每一个shard会在本地查询而后添加结果到本地的排序好的优先级队列里面。

3,每一个shard返回docId和全部参与排序字段的值例如_score到优先级队列里面,而后再返回给coordinating节点也就是Node 3,而后Node 3负责将全部shard里面的数据给合并到一个全局的排序的列表。

上面提到一个术语叫coordinating node,这个节点是当search请求随机负载的发送到一个节点上,而后这个节点就会成为一个coordinating node,它的职责是广播search请求到全部相关的shard上,而后合并他们的响应结果到一个全局的排序列表中而后进行第二个fetch阶段,注意这个结果集仅仅包含docId和全部排序的字段值,search请求能够被主shard或者副本shard处理,这也是为何咱们说增长副本的个数就能增长搜索吞吐量的缘由,coordinating节点将会经过round-robin的方式自动负载均衡。排序

(二)fetch(读取阶段)索引

query阶段标识了那些文档知足了该次的search请求,可是咱们仍然须要检索回document整条数据,这个阶段称为fetch队列

image

流程以下:

1,coordinating 节点标识了那些document须要被拉取出来,并发送一个批量的mutil get请求到相关的shard上

2,每一个shard加载相关document,若是须要他们将会被返回到coordinating 节点上

3,一旦全部的document被拉取回来,coordinating节点将会返回结果集到客户端上。

这里须要注意,coordinating节点拉取的时候只拉取须要被拉取的数据,好比from=90,size=10,那么fetch只会读取须要被读取的10条数据,这10条数据可能在一个shard上,也可能在多个shard上因此 coordinating节点会构建一个multi-get请求并发送到每个shard上,每一个shard会根据须要从_source字段里面获取数据,一旦全部的数据返回,coordinating节点会组装数据进入单个response里面而后将其返回给最终的client。

总结:

本文介绍了es的分布式search的查询流程分为query和fetch两个阶段,在query阶段会从全部的shard上读取相关document的docId及相关的排序字段值,并最终在coordinating节点上收集全部的结果数进入一个全局的排序列表后,而后获取根据from+size指定page页的数据,获取这些docId后再构建一个multi-get请求发送相关的shard上从_source里面获取须要加载的数据,最终再返回给client端,至此整个search请求流程执行完毕,至于为何es要经过两个阶段来完成一次search请求而不是一次搞定,欢迎你们在评论区讨论。

相关文章
相关标签/搜索