ES 5.6.4 源码解析---Netty框架处理http请求

#简介
阅读ES源码首先需要了解http请求如何转发到具体的实现类中,否则很可能本各种莫名其妙的跳转搞晕。ES 利用Netty框架处理http请求。在ES2.x中用的netty3版本,在5.X中默认使用netty4版本,当然可通过如下启动方式切换到netty3版本:

./bin/elasticsearch -Ehttp.type=netty3

在看源码之前先介绍一下netty的基本概念。
#netty基本介绍
在Netty里,Channel是通讯的载体,而ChannelHandler负责Channel中的逻辑处理。
那么ChannelPipeline是什么呢?我觉得可以理解为ChannelHandler的容器:一个Channel包含一个ChannelPipeline,所有ChannelHandler都会注册到ChannelPipeline中,并按顺序组织起来。
在Netty中,ChannelEvent是数据或者状态的载体,例如传输的数据对应MessageEvent,状态的改变对应ChannelStateEvent。当对Channel进行操作时,会产生一个ChannelEvent,并发送到ChannelPipeline。ChannelPipeline会选择一个ChannelHandler进行处理。这个ChannelHandler处理之后,可能会产生新的ChannelEvent,并流转到下一个ChannelHandler。
这里写图片描述
例如,一个数据最开始是一个MessageEvent,它附带了一个未解码的原始二进制消息ChannelBuffer,然后某个Handler将其解码成了一个数据对象,并生成了一个新的MessageEvent,并传递给下一步进行处理。
到了这里,可以看到,其实Channel的核心流程位于ChannelPipeline中。
netty部分参考Netty那点事(三)Channel中的Pipeline
#代码走读
####netty的启动
netty的启动是在ES的启动代码中调用的,这里对于ES的启动不做重点解析,仅提供如下代码跳转路径,快速从ES入口代码定位到netty的启动代码:

Elasticsearch::main(final String[] args)  -> int status = main(args, elasticsearch, Terminal.DEFAULT);
Elasticsearch::main(final String[] args, final Elasticsearch elasticsearch, final Terminal terminal) -> return elasticsearch.main(args, terminal);
Command::main(String[] args, Terminal terminal) -> mainWithoutErrorHandling(args, terminal);
Command::mainWithoutErrorHandling(String[] args, Terminal terminal) -> execute(terminal, options);
EnvironmentAwareCommand::execute(Terminal terminal, OptionSet options) -> execute(terminal, options, createEnv(terminal, settings));
Elasticsearch::execute(Terminal terminal, OptionSet options, Environment env) -> init(daemonize, pidFile, quiet, env);
Elasticsearch::init(final boolean daemonize, final Path pidFile, final boolean quiet, Environment initialEnv) -> Bootstrap.init(!daemonize, pidFile, quiet, initialEnv);
Bootstrap::init(final boolean foreground, final Path pidFile, final boolean quiet, final Environment initialEnv) -> INSTANCE.start();
Bootstrap::void start() -> node.start();
Node::Node start() -> injector.getInstance(HttpServerTransport.class).start();
AbstractLifecycleComponent::void start() -> doStart();
Netty4HttpServerTransport::void doStart() 
serverBootstrap = new ServerBootstrap();
            if (blockingServer) {
                serverBootstrap.group(new OioEventLoopGroup(workerCount, daemonThreadFactory(settings,
                    HTTP_SERVER_WORKER_THREAD_NAME_PREFIX)));
                serverBootstrap.channel(OioServerSocketChannel.class);
            } else {
                serverBootstrap.group(new NioEventLoopGroup(workerCount, daemonThreadFactory(settings,
                    HTTP_SERVER_WORKER_THREAD_NAME_PREFIX)));
                serverBootstrap.channel(NioServerSocketChannel.class);
            }
			
            serverBootstrap.childHandler(configureServerChannelHandler());

serverBootstrap.channel 创建了channel,serverBootstrap.childHandler(configureServerChannelHandler()); 设置了channelhandler。

public ChannelHandler configureServerChannelHandler() {
        return new HttpChannelHandler(this, detailedErrorsEnabled, threadPool.getThreadContext());
    }

    protected static class HttpChannelHandler extends ChannelInitializer<Channel> {

        private final Netty4HttpServerTransport transport;
        private final Netty4HttpRequestHandler requestHandler;

        protected HttpChannelHandler(
                final Netty4HttpServerTransport transport,
                final boolean detailedErrorsEnabled,
                final ThreadContext threadContext) {
            this.transport = transport;
            this.requestHandler = new Netty4HttpRequestHandler(transport, detailedErrorsEnabled, threadContext);
        }

Netty4HttpRequestHandler将用于处理http请求。

protected void initChannel(Channel ch) throws Exception {
            ...
            ch.pipeline().addLast("handler", requestHandler);
        }

将http请求处理handler加入netty的pipeline中。http请求将会由Netty4HttpRequestHandler的channelRead0接收

protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        ...
        if (request.decoderResult().isSuccess()) {
            serverTransport.dispatchRequest(httpRequest, channel);
        } else {
            assert request.decoderResult().isFailure();
            serverTransport.dispatchBadRequest(httpRequest, channel, request.decoderResult().cause());
        }
    }

接收到的请求被Netty4HttpServerTransport::dispatchRequest分发

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

接着被RestController::dispatchRequest 分发

public void dispatchRequest(RestRequest request, RestChannel channel, ThreadContext threadContext) {
        ...
                dispatchRequest(request, responseChannel, client, threadContext, handler);
            }
        } catch (Exception e) {
           ...        }
    }

 void dispatchRequest(final RestRequest request, final RestChannel channel, final NodeClient client, ThreadContext threadContext,
                         final RestHandler handler) throws Exception {
        ...
            if (handler == null) {
            ...
            } else {
                final RestHandler wrappedHandler = Objects.requireNonNull(handlerWrapper.apply(handler));
                wrappedHandler.handleRequest(request, channel, client);
            }
        }
    }

BaseRestHandler::wrappedHandler.handleRequest 继续处理请求

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"));
        }

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

final RestChannelConsumer action = prepareRequest(request, client); 会根据具体的请求类型生产对应的action,例如一个bulk请求,它的实现代码如下:

@Override
    public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
        BulkRequest bulkRequest = Requests.bulkRequest();
        String defaultIndex = request.param("index");
        String defaultType = request.param("type");
        String defaultRouting = request.param("routing");
        FetchSourceContext defaultFetchSourceContext = FetchSourceContext.parseFromRestRequest(request);
        String fieldsParam = request.param("fields");
        if (fieldsParam != null) {
            DEPRECATION_LOGGER.deprecated("Deprecated field [fields] used, expected [_source] instead");
        }
        String[] defaultFields = fieldsParam != null ? Strings.commaDelimitedListToStringArray(fieldsParam) : null;
        String defaultPipeline = request.param("pipeline");
        String waitForActiveShards = request.param("wait_for_active_shards");
        if (waitForActiveShards != null) {
            bulkRequest.waitForActiveShards(ActiveShardCount.parseString(waitForActiveShards));
        }
        bulkRequest.timeout(request.paramAsTime("timeout", BulkShardRequest.DEFAULT_TIMEOUT));
        bulkRequest.setRefreshPolicy(request.param("refresh"));
        bulkRequest.add(request.requiredContent(), defaultIndex, defaultType, defaultRouting, defaultFields,
            defaultFetchSourceContext, defaultPipeline, null, allowExplicitIndex, request.getXContentType());

        return channel -> client.bulk(bulkRequest, new RestStatusToXContentListener<>(channel));
    }

解析出请求中的index,type,routing等信息,重构出builRequest,然后调用AbstractClient::client.bulk

	@Override
    public void bulk(final BulkRequest request, final ActionListener<BulkResponse> listener) {
        execute(BulkAction.INSTANCE, request, listener);
    }
    @Override
    public final <Request extends ActionRequest, Response extends ActionResponse, RequestBuilder extends ActionRequestBuilder<Request, Response, RequestBuilder>> void execute(
            Action<Request, Response, RequestBuilder> action, Request request, ActionListener<Response> listener) {
        listener = threadedWrapper.wrap(listener);
        doExecute(action, request, listener);
    }

调用客户的节点NodeClient::doExcecute

@Override
    public <    Request extends ActionRequest,
                Response extends ActionResponse,
                RequestBuilder extends ActionRequestBuilder<Request, Response, RequestBuilder>
            > void doExecute(Action<Request, Response, RequestBuilder> action, Request request, ActionListener<Response> listener) {
        // Discard the task because the Client interface doesn't use it.
        executeLocally(action, request, listener);
    }
    public <    Request extends ActionRequest,
                Response extends ActionResponse
            > Task executeLocally(GenericAction<Request, Response> action, Request request, ActionListener<Response> listener) {
        return transportAction(action).execute(request, listener);
    }

调用TransportAction的execute

Task task = taskManager.register("transport", actionName, request);
        if (task == null) {
            execute(null, request, listener);
        } else {
            execute(task, request, new ActionListener<Response>() {
                @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;
    }
public final void execute(Task task, Request request, ActionListener<Response> listener) {
        ActionRequestValidationException validationException = request.validate();
        if (validationException != null) {
            listener.onFailure(validationException);
            return;
        }

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

        RequestFilterChain<Request, Response> requestFilterChain = new RequestFilterChain<>(this, logger);
        requestFilterChain.proceed(task, actionName, request, listener);
    }
 @Override
        public void proceed(Task task, String actionName, Request request, ActionListener<Response> 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);
            }
        }

this.action.doExecute(task, request, listener); 实际调用的是 TransportBulkAction::doExecute,那么怎么从action对应出TransportBulkAction的呢?
ActionModule::setupActions已经建立起对应关系

actions.register(BulkAction.INSTANCE, TransportBulkAction.class,
                TransportShardBulkAction.class);
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值