elasticsearch源码分析-07GET查询流程

GET查询流程

ES的读取分为Get和search两种,get是根据id从索引中获取内容,而search是根据关键词从倒排索引中获取内容

get请求的处理在actionModule中进行注册

//get请求处理
registerHandler.accept(new RestGetAction());

请求的路由为

public List<Route> routes() {
    return unmodifiableList(asList(
        new Route(GET, "/{index}/_doc/{id}"),
        new Route(HEAD, "/{index}/_doc/{id}"),
        // Deprecated typed endpoints.
        new Route(GET, "/{index}/{type}/{id}"),
        new Route(HEAD, "/{index}/{type}/{id}")));
}

当节点接收到rest请求后会分发到不同的handler进行处理

void dispatchRequest(final RestRequest restRequest, final RestChannel channel, final Throwable badRequestCause) {
    final ThreadContext threadContext = threadPool.getThreadContext();
    try (ThreadContext.StoredContext ignore = threadContext.stashContext()) {
        //错误请求处理
        if (badRequestCause != null) {
            dispatcher.dispatchBadRequest(channel, threadContext, badRequestCause);
        } else {
            //正常请求处理
            dispatcher.dispatchRequest(restRequest, channel, threadContext);
        }
    }
}

public void dispatchRequest(RestRequest request, RestChannel channel, ThreadContext threadContext) {
    //小图标请求处理
    if (request.rawPath().equals("/favicon.ico")) {
        handleFavicon(request.method(), request.uri(), channel);
        return;
    }
    try {
        //处理rest请求
        tryAllHandlers(request, channel, threadContext);
    } catch (Exception e) {
        try {
            channel.sendResponse(new BytesRestResponse(channel, e));
        } catch (Exception inner) {
            inner.addSuppressed(e);
            logger.error(() ->
                         new ParameterizedMessage("failed to send failure response for uri [{}]", request.uri()), inner);
        }
    }
}

最终执行到BaseRestHandler的handleRequest方法

@Override
    public final void handleRequest(RestRequest request, RestChannel channel, NodeClient client) throws Exception {
        // prepare the request for execution; has the side effect of touching the request parameters
        //处理请求
        final RestChannelConsumer action = prepareRequest(request, client);

        // validate unconsumed params, but we must exclude params used to format the response
        // use a sorted set so the unconsumed parameters appear in a reliable sorted order
        final SortedSet<String> unconsumedParams =
            request.unconsumedParams().stream().filter(p -> !responseParams().contains(p)).collect(Collectors.toCollection(TreeSet::new));

        // validate the non-response params
        if (!unconsumedParams.isEmpty()) {
            final Set<String> candidateParams = new HashSet<>();
            candidateParams.addAll(request.consumedParams());
            candidateParams.addAll(responseParams());
            throw new IllegalArgumentException(unrecognized(request, unconsumedParams, candidateParams, "parameter"));
        }

        if (request.hasContent() && request.isContentConsumed() == false) {
            throw new IllegalArgumentException("request [" + request.method() + " " + request.path() + "] does not support having a body");
        }

        usageCount.increment();
        // execute the action
        action.accept(channel);
    }

调用prepareRequest将请求参数封装近request中

@Override
    public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
        GetRequest getRequest;
        //处理type类型默认_doc
        if (request.hasParam("type")) {
            deprecationLogger.deprecatedAndMaybeLog("get_with_types", TYPES_DEPRECATION_MESSAGE);
            getRequest = new GetRequest(request.param("index"), request.param("type"), request.param("id"));
        } else {
            getRequest = new GetRequest(request.param("index"), request.param("id"));
        }
        //是否设置查询前需要执行refresh
        getRequest.refresh(request.paramAsBoolean("refresh", getRequest.refresh()));
        //是否外部指定了路由
        getRequest.routing(request.param("routing"));
        //可以指定从主分片获取或者从本地获取,默认是从多个分片中随机选择一个
        getRequest.preference(request.param("preference"));
        //是否是实时查询,也就是不受refresh影响,如果查询时候文档已经更新但是没有执行refresh,那么会首先执行一次refresh,使文档可见
        getRequest.realtime(request.paramAsBoolean("realtime", getRequest.realtime()));
        //校验
        if (request.param("fields") != null) {
            throw new IllegalArgumentException("the parameter [fields] is no longer supported, " +
                "please use [stored_fields] to retrieve stored fields or [_source] to load the field from _source");
        }
        //mapping中store设置为true的字段,这里指定返回字段
        final String fieldsParam = request.param("stored_fields");
        if (fieldsParam != null) {
            final String[] fields = Strings.splitStringByCommaToArray(fieldsParam);
            if (fields != null) {
                getRequest.storedFields(fields);
            }
        }
        //指定查询版本号
        getRequest.version(RestActions.parseVersion(request));
        //版本号类型是内部还是外部
        getRequest.versionType(VersionType.fromString(request.param("version_type"), getRequest.versionType()));
        //指定查询_source
        getRequest.fetchSourceContext(FetchSourceContext.parseFromRestRequest(request));

        return channel -> client.get(getRequest, new RestToXContentListener<GetResponse>(channel) {
            @Override
            protected RestStatus getStatus(final GetResponse response) {
                return response.isExists() ? OK : NOT_FOUND;
            }
        });
    }

调用doExecute方法

public <    Request extends ActionRequest,
                Response extends ActionResponse
            > Task executeLocally(ActionType<Response> action, Request request, ActionListener<Response> listener) {
        //获取transportAction开始执行
        return transportAction(action).execute(request, listener);
    }

获取action执行,这里action的注册在actionModule中

//get查询处理
actions.register(GetAction.INSTANCE, TransportGetAction.class);

而TransportGetAction继承了TransportSingleShardAction最终调用它的doExecute方法

@Override
protected void doExecute(Task task, Request request, ActionListener<Response> listener) {
    new AsyncSingleAction(request, listener).start();
}

private AsyncSingleAction(Request request, ActionListener<Response> listener) {
            this.listener = listener;

            ClusterState clusterState = clusterService.state();
            if (logger.isTraceEnabled()) {
                logger.trace("executing [{}] based on cluster state version [{}]", request, clusterState.version());
            }
            nodes = clusterState.nodes();
            ClusterBlockException blockException = checkGlobalBlock(clusterState);
            if (blockException != null) {
                throw blockException;
            }

            String concreteSingleIndex;
            //解析索引
            if (resolveIndex(request)) {
                concreteSingleIndex = indexNameExpressionResolver.concreteSingleIndex(clusterState, request).getName();
            } else {
                concreteSingleIndex = request.index();
            }
            this.internalRequest = new InternalRequest(request, concreteSingleIndex);
            //解析请求
            resolveRequest(clusterState, internalRequest);

            blockException = checkRequestBlock(clusterState, internalRequest);
            if (blockException != null) {
                throw blockException;
            }
            //查询分片如果没有指定就随机选择分片,如果是本地则为null
            this.shardIt = shards(clusterState, internalRequest);
        }

构建AsyncSingleAction调用start方法

public void start() {
            if (shardIt == null) {
                //本地执行
                // just execute it on the local node
                final Writeable.Reader<Response> reader = getResponseReader();
                transportService.sendRequest(clusterService.localNode(), transportShardAction, internalRequest.request(),
                    new TransportResponseHandler<Response>() {
                    @Override
                    public Response read(StreamInput in) throws IOException {
                        return reader.read(in);
                    }

                    @Override
                    public String executor() {
                        return ThreadPool.Names.SAME;
                    }

                    @Override
                    public void handleResponse(final Response response) {
                        listener.onResponse(response);
                    }

                    @Override
                    public void handleException(TransportException exp) {
                        listener.onFailure(exp);
                    }
                });
            } else {
                perform(null);
            }
        }

如果随机分片是本地执行调用sendRequest方法

public <T extends TransportResponse> void sendRequest(final DiscoveryNode node, final String action,
                                                                final TransportRequest request,
                                                                final TransportResponseHandler<T> handler) {
        final Transport.Connection connection;
        try {
            //获取连接分为本地和远程
            connection = getConnection(node);
        } catch (final NodeNotConnectedException ex) {
            // the caller might not handle this so we invoke the handler
            handler.handleException(ex);
            return;
        }
        sendRequest(connection, action, request, TransportRequestOptions.EMPTY, handler);
    }

public Transport.Connection getConnection(DiscoveryNode node) {
        //本地节点
        if (isLocalNode(node)) {
            return localNodeConnection;
        } else {
            return connectionManager.getConnection(node);
        }
    }

首先获取连接,连接分为本地和远程

  • 本地执行
@Override
public void sendRequest(long requestId, String action, TransportRequest request, TransportRequestOptions options)
    throws TransportException {
    sendLocalRequest(requestId, action, request, options);
}

获取线程池然后执行,最终都会调用processMessageReceived方法

reg.processMessageReceived(request, channel);

public void processMessageReceived(Request request, TransportChannel channel) throws Exception {
    //注册没有父任务的任务
    final Task task = taskManager.register(channel.getChannelType(), action, request);
    boolean success = false;
    try {
        handler.messageReceived(request, new TaskTransportChannel(taskManager, task, channel), task);
        success = true;
    } finally {
        if (success == false) {
            taskManager.unregister(task);
        }
    }
}

这里的handler在创建TransportSingleShardAction中

//注册请求的处理器
        transportService.registerRequestHandler(transportShardAction, ThreadPool.Names.SAME, request, new ShardTransportHandler());

protected void asyncShardOperation(Request request, ShardId shardId, ActionListener<Response> listener) throws IOException {
        threadPool.executor(getExecutor(request, shardId))
            .execute(ActionRunnable.supply(listener, () -> shardOperation(request, shardId)));
    }

继续调用TransportGetAction的shardOperation方法

@Override
protected GetResponse shardOperation(GetRequest request, ShardId shardId) {
    IndexService indexService = indicesService.indexServiceSafe(shardId.getIndex());
    IndexShard indexShard = indexService.getShard(shardId.id());

    if (request.refresh() && !request.realtime()) {
        indexShard.refresh("refresh_flag_get");
    }
    //调用get查询
    GetResult result = indexShard.getService().get(request.type(), request.id(), request.storedFields(),
                                                   request.realtime(), request.version(), request.versionType(), request.fetchSourceContext());
    return new GetResponse(result);
}

最终调用innerGet方法

private GetResult get(String type, String id, String[] gFields, boolean realtime, long version, VersionType versionType,
                          long ifSeqNo, long ifPrimaryTerm, FetchSourceContext fetchSourceContext) {
        currentMetric.inc();
        try {
            long now = System.nanoTime();
            GetResult getResult =
                //查询
                innerGet(type, id, gFields, realtime, version, versionType, ifSeqNo, ifPrimaryTerm, fetchSourceContext);

            if (getResult.isExists()) {
                existsMetric.inc(System.nanoTime() - now);
            } else {
                missingMetric.inc(System.nanoTime() - now);
            }
            return getResult;
        } finally {
            currentMetric.dec();
        }
    }

调用engine读取数据信息

public GetResult get(Get get, BiFunction<String, SearcherScope, Engine.Searcher> searcherFactory) throws EngineException {
        assert Objects.equals(get.uid().field(), IdFieldMapper.NAME) : get.uid().field();
        try (ReleasableLock ignored = readLock.acquire()) {
            ensureOpen();
            SearcherScope scope;
            //处理实时查询
            if (get.realtime()) {
                VersionValue versionValue = null;
                try (Releasable ignore = versionMap.acquireLock(get.uid().bytes())) {
                    // we need to lock here to access the version map to do this truly in RT
                    versionValue = getVersionFromMap(get.uid().bytes());
                }
                //处理查询时候指定的版本号
                if (versionValue != null) {
                    if (versionValue.isDelete()) {
                        return GetResult.NOT_EXISTS;
                    }
                    if (get.versionType().isVersionConflictForReads(versionValue.version, get.version())) {
                        throw new VersionConflictEngineException(shardId, get.id(),
                            get.versionType().explainConflictForReads(versionValue.version, get.version()));
                    }
                    if (get.getIfSeqNo() != SequenceNumbers.UNASSIGNED_SEQ_NO && (
                        get.getIfSeqNo() != versionValue.seqNo || get.getIfPrimaryTerm() != versionValue.term
                        )) {
                        throw new VersionConflictEngineException(shardId, get.id(),
                            get.getIfSeqNo(), get.getIfPrimaryTerm(), versionValue.seqNo, versionValue.term);
                    }
                    if (get.isReadFromTranslog()) {
                        // this is only used for updates - API _GET calls will always read form a reader for consistency
                        // the update call doesn't need the consistency since it's source only + _parent but parent can go away in 7.0
                        if (versionValue.getLocation() != null) {
                            try {
                                Translog.Operation operation = translog.readOperation(versionValue.getLocation());
                                if (operation != null) {
                                    // in the case of a already pruned translog generation we might get null here - yet very unlikely
                                    final Translog.Index index = (Translog.Index) operation;
                                    TranslogLeafReader reader = new TranslogLeafReader(index);
                                    return new GetResult(new Engine.Searcher("realtime_get", reader,
                                        IndexSearcher.getDefaultSimilarity(), null, IndexSearcher.getDefaultQueryCachingPolicy(), reader),
                                        new VersionsAndSeqNoResolver.DocIdAndVersion(0, index.version(), index.seqNo(), index.primaryTerm(),
                                            reader, 0), true);
                                }
                            } catch (IOException e) {
                                maybeFailEngine("realtime_get", e); // lets check if the translog has failed with a tragic event
                                throw new EngineException(shardId, "failed to read operation from translog", e);
                            }
                        } else {
                            trackTranslogLocation.set(true);
                        }
                    }
                    assert versionValue.seqNo >= 0 : versionValue;
                    refreshIfNeeded("realtime_get", versionValue.seqNo);
                }
                //内部
                scope = SearcherScope.INTERNAL;
            } else {
                // we expose what has been externally expose in a point in time snapshot via an explicit refresh
                //外部
                scope = SearcherScope.EXTERNAL;
            }

            // no version, get the version from the index, we know that we refresh on flush
            //调用searcher读取数据
            return getFromSearcher(get, searcherFactory, scope);
        }
    }

根据查询信息读取lucene数据

//根据上面getResult的信息获取数据
            return innerGetLoadFromStoredFields(type, id, gFields, fetchSourceContext, get, mapperService);

最后将查询到的数据返回

  • 分片为非本地分片
//远端
perform(null);

private void perform(@Nullable final Exception currentFailure) {
            Exception lastFailure = this.lastFailure;
            if (lastFailure == null || TransportActions.isReadOverrideException(currentFailure)) {
                lastFailure = currentFailure;
                this.lastFailure = currentFailure;
            }
            //路由信息
            final ShardRouting shardRouting = shardIt.nextOrNull();
            if (shardRouting == null) {
                Exception failure = lastFailure;
                if (failure == null || isShardNotAvailableException(failure)) {
                    failure = new NoShardAvailableActionException(null,
                        LoggerMessageFormat.format("No shard available for [{}]", internalRequest.request()), failure);
                } else {
                    logger.debug(() -> new ParameterizedMessage("{}: failed to execute [{}]", null,
                        internalRequest.request()), failure);
                }
                listener.onFailure(failure);
                return;
            }
            //node节点
            DiscoveryNode node = nodes.get(shardRouting.currentNodeId());
            if (node == null) {
                onFailure(shardRouting, new NoShardAvailableActionException(shardRouting.shardId()));
            } else {
                internalRequest.request().internalShardId = shardRouting.shardId();
                if (logger.isTraceEnabled()) {
                    logger.trace(
                            "sending request [{}] to shard [{}] on node [{}]",
                            internalRequest.request(),
                            internalRequest.request().internalShardId,
                            node
                    );
                }
                final Writeable.Reader<Response> reader = getResponseReader();
                transportService.sendRequest(node, transportShardAction, internalRequest.request(),
                    new TransportResponseHandler<Response>() {

                        @Override
                        public Response read(StreamInput in) throws IOException {
                            return reader.read(in);
                        }

                        @Override
                        public String executor() {
                            return ThreadPool.Names.SAME;
                        }

                        @Override
                        public void handleResponse(final Response response) {
                            listener.onResponse(response);
                        }

                        @Override
                        public void handleException(TransportException exp) {
                            onFailure(shardRouting, exp);
                        }
                });
            }
        }
    }

就是将请求转发到其他节点执行,处理逻辑和上面的逻辑一致,其他节点执行后会把数据返回,然后节点把数据返回给用户请求

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值