Elasticsearch原理学习--Rest请求处理流程

         之前我们已经通过博客《Elasticsearch学习--ES源码下载、导入及运行》了解学习到如何在本地将Elasticsearch服务运行起来,整个2018年下半年过去了,由于在学习其他知识,对于ES学习这块就暂时先放下的,接下来我们就对ES有一个系统的学习。

这篇博客我们通过访问:http://localhost:9200/ 来简单了解一下ES对请求的处理流程。 

1、Netty4HttpRequestHandler

  ES提供Netty4HttpRequestHandler作为Http请求的处理器,基于Netty(高性能网络框架)实现,提供channelRead0方法来接收请求。在channelRead0方法中主要创建对象Netty4HttpRequest和Netty4HttpChannel,接下来交由Netty4HttpServerTransport去处理。

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        
		//省略部分代码
		
        final Netty4HttpRequest httpRequest;
        try {
            httpRequest = new Netty4HttpRequest(serverTransport.xContentRegistry, copy, ctx.channel());
        } catch (Exception ex) {
            if (pipelinedRequest != null) {
                pipelinedRequest.release();
            }
            throw ex;
        }
        final Netty4HttpChannel channel =
                new Netty4HttpChannel(serverTransport, httpRequest, pipelinedRequest, detailedErrorsEnabled, threadContext);

        if (request.decoderResult().isSuccess()) {
            serverTransport.dispatchRequest(httpRequest, channel);
        } else {
            assert request.decoderResult().isFailure();
            serverTransport.dispatchBadRequest(httpRequest, channel, request.decoderResult().cause());
        }
    }

2、Netty4HttpServerTransport

在Netty4HttpServerTransport的dispatchRequest中没有做过多的业务处理,然后交由Dispatcher去处理。

void dispatchRequest(final RestRequest request, final RestChannel channel) {
        final ThreadContext threadContext = threadPool.getThreadContext();
        try (ThreadContext.StoredContext ignore = threadContext.stashContext()) {
            dispatcher.dispatchRequest(request, channel, threadContext);
        }
    }

3、Dispatcher

  Dispatcher的实现类RestController用来处理所有的Http请求,在tryAllHandlers中会查找所有的请求处理器来处理请求。

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

在tryAllHandlers中会查找RestHandler处理器

void tryAllHandlers(final RestRequest request, final RestChannel channel, final ThreadContext threadContext) throws Exception {

		//省略部分代码

        //根据请求查找所有的处理器
        Iterator allHandlers = getAllHandlers(request);
        for (Iterator it = allHandlers; it.hasNext(); ) {
            final Optional mHandler = Optional.ofNullable(it.next()).flatMap(mh -> mh.getHandler(request.method()));
            requestHandled = dispatchRequest(request, channel, client, mHandler);
            if (requestHandled) {
                break;
            }
        }

        // If request has not been handled, fallback to a bad request error.
        if (requestHandled == false) {
            handleBadRequest(request, channel);
        }
    }

在dispatchRequest方法中会根据查找对应的RestHandler的实现类,这样调用RestHandler的handleRequest方法,处理Http请求。

boolean dispatchRequest(final RestRequest request, final RestChannel channel, final NodeClient client,
                            final Optional mHandler) throws Exception {
       
		//省略部分代码
        final RestHandler wrappedHandler = mHandler.map(h -> handlerWrapper.apply(h)).get();
        wrappedHandler.handleRequest(request, responseChannel, client);
        
		//省略部分代码
		
        return requestHandled;
    }

 RestHandler的实现类RestMainAction

Elasticsearch原理学习--Rest请求处理流程_第1张图片

4、RestHandler

handleRequest的实现方法在抽象类BaseRestHandler中,在这个方法中调用抽象方法prepareRequest获取RestChannelConsumer,然后调用action.accept(channel)方法,这里ES采用了 lambda编程,最终的实现及调用者在prepareRequest方法中。

    @Override
    public final void handleRequest(RestRequest request, RestChannel channel, NodeClient client) throws Exception {
       
        //构建调用者
        final RestChannelConsumer action = prepareRequest(request, client);

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

prepareRequest在具体的Action的实现类中,在这里就是在RestMainAction中,最终会调用NodeClient的execute方法。

 @Override
    public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
        //执行NodeClient的execute方法
        return channel -> client.execute(MainAction.INSTANCE, new MainRequest(), new RestBuilderListener(channel) {
            @Override
            public RestResponse buildResponse(MainResponse mainResponse, XContentBuilder builder) throws Exception {
                return convertMainResponse(mainResponse, request, builder);
            }
        });
    }

5、NodeClient

NodeClient的execute方法在父类AbstractClient中,会创建监听器Listener,执行doExecute方法。

    @Override
    public final > void execute(
            Action action, Request request, ActionListener listener) {
        listener = threadedWrapper.wrap(listener);
        doExecute(action, request, listener);
    }

在doExecute方法中会根据action获取TransportAction的实现类,这里获取的是

public <    Request extends ActionRequest,
                Response extends ActionResponse
            > Task executeLocally(GenericAction action, Request request, ActionListener listener) {
        return transportAction(action).execute(request, listener);
    }

6、TransportAction

获取TransportAction的实现类首先调用execute方法

public final Task execute(Request request, ActionListener listener) {

		//注册任务
        Task task = taskManager.register("transport", actionName, request);
        if (task == null) {
            execute(null, request, listener);
        } else {
			//执行任务
            execute(task, request, new ActionListener() {
                @Override
                public void onResponse(Response response) {
                    taskManager.unregister(task);
                    listener.onResponse(response);
                }

                @Override
                public void onFailure(Exception e) {
                    taskManager.unregister(task);
                    listener.onFailure(e);
                }
            });
        }
        return task;
    }

在执行execute方法时会获取请求拦截器链,然后执行拦截器链,类似Web服务的Filter过滤器。

 public final void execute(Task task, Request request, ActionListener listener) {
        ActionRequestValidationException validationException = request.validate();
        if (validationException != null) {
            listener.onFailure(validationException);
            return;
        }

        if (task != null && request.getShouldStoreResult()) {
            listener = new TaskResultStoringActionListener<>(taskManager, task, listener);
        }

        RequestFilterChain requestFilterChain = new RequestFilterChain<>(this, logger);
        requestFilterChain.proceed(task, actionName, request, listener);
    }

 在RequestFilterChain中执行proceed方法,最终还是执行action的doExecute方法。

        @Override
        public void proceed(Task task, String actionName, Request request, ActionListener listener) {
            int i = index.getAndIncrement();
            try {
                if (i < this.action.filters.length) {
                    this.action.filters[i].apply(task, actionName, request, listener, this);
                } else if (i == this.action.filters.length) {
                    this.action.doExecute(task, request, listener);
                } else {
                    listener.onFailure(new IllegalStateException("proceed was called too many times"));
                }
            } catch(Exception e) {
                logger.trace("Error during transport action execution.", e);
                listener.onFailure(e);
            }
        }

 TransportAction的实现类TransportMainAction调用doExecute,在此方法中组装数据然后调用ActionListener的onResponse方法返回数据。

     @Override
    protected void doExecute(MainRequest request, ActionListener listener) {
        ClusterState clusterState = clusterService.state();
        assert Node.NODE_NAME_SETTING.exists(settings);
        final boolean available = clusterState.getBlocks().hasGlobalBlock(RestStatus.SERVICE_UNAVAILABLE) == false;
        listener.onResponse(
            new MainResponse(Node.NODE_NAME_SETTING.get(settings), Version.CURRENT, clusterState.getClusterName(),
                    clusterState.metaData().clusterUUID(), Build.CURRENT, available));
    }

 7、ActionListener

ActionListener的实现类RestActionListener提供onResponse方法

    @Override
    public final void onResponse(Response response) {
        try {
            processResponse(response);
        } catch (Exception e) {
            onFailure(e);
        }
    }

 在子类RestResponseListener中会构建返回值,调用Netty4HttpChannel的sendResponse方法返回数据

    @Override
    protected final void processResponse(Response response) throws Exception {
        //返回数据
        channel.sendResponse(buildResponse(response));
    }

对应查询:http://localhost:9200地址返回的数据在RestBuilderListener中构建

new RestBuilderListener(channel) {
            @Override
            public RestResponse buildResponse(MainResponse mainResponse, XContentBuilder builder) throws Exception {
                return convertMainResponse(mainResponse, request, builder);
            }
        });

8、 Netty4HttpChannel

在Nett4HttpChannel中调用sendResponse方法返回数据。

	@Override
    public void sendResponse(RestResponse response) {
        // if the response object was created upstream, then use it;
        // otherwise, create a new one
        ByteBuf buffer = Netty4Utils.toByteBuf(response.content());
        final FullHttpResponse resp;
        if (HttpMethod.HEAD.equals(nettyRequest.method())) {
            resp = newResponse(Unpooled.EMPTY_BUFFER);
        } else {
            resp = newResponse(buffer);
        }
        resp.setStatus(getStatus(response.status()));

        Netty4CorsHandler.setCorsResponseHeaders(nettyRequest, resp, transport.getCorsConfig());

        String opaque = nettyRequest.headers().get("X-Opaque-Id");
        if (opaque != null) {
            setHeaderField(resp, "X-Opaque-Id", opaque);
        }

        // Add all custom headers
        addCustomHeaders(resp, response.getHeaders());
        addCustomHeaders(resp, threadContext.getResponseHeaders());

        BytesReference content = response.content();
        boolean releaseContent = content instanceof Releasable;
        boolean releaseBytesStreamOutput = bytesOutputOrNull() instanceof ReleasableBytesStreamOutput;
        try {
            // If our response doesn't specify a content-type header, set one
            setHeaderField(resp, HttpHeaderNames.CONTENT_TYPE.toString(), response.contentType(), false);
            // If our response has no content-length, calculate and set one
            setHeaderField(resp, HttpHeaderNames.CONTENT_LENGTH.toString(), String.valueOf(buffer.readableBytes()), false);

            addCookies(resp);

            final ChannelPromise promise = channel.newPromise();

            if (releaseContent) {
                promise.addListener(f -> ((Releasable)content).close());
            }

            if (releaseBytesStreamOutput) {
                promise.addListener(f -> bytesOutputOrNull().close());
            }

            if (isCloseConnection()) {
                promise.addListener(ChannelFutureListener.CLOSE);
            }

            final Object msg;
            if (pipelinedRequest != null) {
                msg = pipelinedRequest.createHttpResponse(resp, promise);
            } else {
                msg = resp;
            }
            channel.writeAndFlush(msg, promise);
            releaseContent = false;
            releaseBytesStreamOutput = false;
        } finally {
            if (releaseContent) {
                ((Releasable) content).close();
            }
            if (releaseBytesStreamOutput) {
                bytesOutputOrNull().close();
            }
            if (pipelinedRequest != null) {
                pipelinedRequest.release();
            }
        }
    }

9、请求执行流程图:

Elasticsearch原理学习--Rest请求处理流程_第2张图片 请求处理流程

 

 

你可能感兴趣的:(Elasticsearch原理学习--Rest请求处理流程)