ElasticSearch查询流程详解

一、前言

前面已经介绍了ElasticSearch的写入流程,了解了ElasticSearch写入时的分布式特性的相关原理。ElasticSearch作为一款具有强大搜索功能的存储引擎,它的读取是什么样的呢?读取相比写入简单得多,但是在使用过程中有哪些需要我们注意的呢?本篇文章会进行详细的分析。

在前面的文章我们已经知道ElasticSearch的读取分为两种GET和SEARCH。这两种操作是有一定的差异的,下面我们先对这两种核心的数据读取方式进行一一分析。

二、GET的流程

2.1 整体流程

(图片来自官网)

以下是从主分片或者副本分片检索文档的步骤顺序:

  • 客户端向 Node 1 发送获取请求
  • 节点使用文档的 _id 来确定文档属于分片 0 。分片 0 的副本分片存在于所有的三个节点上。在这种情况下,它将请求转发到 Node 2
  • Node 2 将文档返回给 Node 1,然后将文档返回给客户端。

注意:

  • 在处理读取请求时,协调节点在每次请求的时候都会通过轮询所有的副本分片来达到负载均衡。
  • 在文档被检索时,已经被索引的文档可能已经存在于主分片上但是还没有复制到副本分片。在这种情况下,副本分片可能会报告文档不存在,但是主分片可能成功返回文档。一旦索引请求成功返回给用户,文档在主分片和副本分片都是可用的

2.2 GET详细流程

2.2.1 协调节点处理过程

在协调节点有个http_server_worker线程池。收到读请求后它的具体过程为:

  • 收到请求,先获取集群的状态信息
  • 根据路由信息计算id是在哪一个分片上
  • 因为一个分片可能有多个副本分片,所以上述的计算结果是一个列表
  • 调用transportServer的sendRequest方法向目标发送请求
  • 上一步的方法内部会检查是否为本地node,如果是的话就不会发送到网络,否则会异步发送
  • 等待数据节点回复,如果成功则返回数据给客户端,否则会重试
  • 重试会发送上述列表的下一个。

2.2.2 数据节点处理过程

数据节点上有一个get线程池。收到了请求后,处理过程为:

  • 在数据节点有个shardTransporthander的messageReceived的入口专门接收协调节点发送的请求
private class ShardTransportHandler implements TransportRequestHandler<Request> {
  @Override
  public void messageReceived(final Request request, final TransportChannel channel, Task task) {
      asyncShardOperation(request, request.internalShardId, new ChannelActionListener<>(channel, transportShardAction, request));
  }
}

  • shardOperation方法会先检查是否需要refresh,然后调用indexShard.getService().get()读取数据并存储到GetResult中。
if (request.refresh() && !request.realtime()) {
  indexShard.refresh("refresh_flag_get");
}
GetResult result = indexShard.getService().get(
                    request.type(), request.id(), 
                    request.storedFields(), request.realtime(),
                    request.version(), request.versionType(), 
                    request.fetchSourceContext());

  • indexShard.getService().get()最终会调用GetResult getResult = innerGet(……)用来获取结果。即ShardGetService#innerGet
private GetResult innerGet(String type, String id, String[] gFields, boolean realtime, long version, VersionType versionType, long ifSeqNo, long ifPrimaryTerm, FetchSourceContext fetchSourceContext) {
      ................
      Engine.GetResult get = null;
          ............
      get = indexShard.get(new Engine.Get(realtime, realtime, type, id, uidTerm).version(version).versionType(versionType).setIfSeqNo(ifSeqNo).setIfPrimaryTerm(ifPrimaryTerm));
          ..........
      if (get == null || get.exists() == false) {
          return new GetResult(shardId.getIndexName(), type, id, UNASSIGNED_SEQ_NO, UNASSIGNED_PRIMARY_TERM, -1, false, null, null, null);
      }
  try {
      return innerGetLoadFromStoredFields(type, id, gFields, fetchSourceContext, get, mapperService);
  } finally {
      get.close();
  }

  • 上面代码的indexShard.get读取真正的数据时会最终调用:
  • org.elasticsearch.index
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值