问题:
同一个索引的多个分片分配在了一个ES节点上,当一次查询需要查找的分片中有多个分片在一个节点上,该ES节点是否会合并查询,使用单个线程查询多个分片?
结论:
每个分片都会使用单独的线程处理。(ES7.17.5)
分析:
我们经常可以看到这样的查询流程图:
那么自然会有这样的思考,如果R0和P1在一个节点,ES协调节点是转发一次还是转发两次?
接下来分析下代码:
1.RestController 将解析Http请求,将RestRequest转化为SearchRequest,org.elasticsearch.plugin.noop.action.search.RestNoopSearchAction#prepareRequest
2.然后再将SearchRequest请求转化为Transport Action,org.elasticsearch.client.node.NodeClient#executeLocally(org.elasticsearch.action.ActionType<Response>, Request, org.elasticsearch.action.ActionListener<Response>)
3.TransportAction的execute方法开始处理请求,
org.elasticsearch.action.support.TransportAction#execute(Request, org.elasticsearch.action.ActionListener<Response>)
4.查询请求开始执行,第一步是计算需要查询的分片,也就是执行请求分发的过程。
org.elasticsearch.action.search.TransportSearchAction#doExecute
第一步:找到目的shard列表(结合routing、preference信息)
org.elasticsearch.action.search.TransportSearchAction#executeSearch
第二步:生成查询请求的调度类,并启动
org.elasticsearch.action.search.TransportSearchAction.SearchAsyncActionProvider#asyncSearchAction
第三步:进入AbstractSearchAsyncAction类,对shardsIts进行遍历,并向shard所在节点发送查询请求。
org.elasticsearch.action.search.AbstractSearchAsyncAction#run
这里可以看到,无论shard是否位于同一个节点,每个shard的请求都会单独发送,并不会合并
for (int i = 0; i < shardsIts.size(); i++) {
final SearchShardIterator shardRoutings = shardsIts.get(i);
assert shardRoutings.skip() == false;
assert shardIndexMap.containsKey(shardRoutings);
int shardIndex = shardIndexMap.get(shardRoutings);
performPhaseOnShard(shardIndex, shardRoutings, shardRoutings.nextOrNull());
}
5.performPhaseOnShard方法转发请求,并设置了一个Listener,用来监听结果
org.elasticsearch.action.search.AbstractSearchAsyncAction#performPhaseOnShard
6.向具体的分片发送Query阶段(query_then_fetch中的query)的子任务,异步处理(asyncSender.sendRequest)
org.elasticsearch.action.search.SearchQueryThenFetchAsyncAction#executePhaseOnShard
7.收集查询结果、执行fetch、整合结果、响应...