6 timing diagram, talk request processing flow Tomcat

A lot of things reflected in the timing diagram has been very clear, no need to be introduced step by step, paper-based map, then be a simple explanation on the part of the content.

  • Drawing tools graphics using PlantUML + Visual Studio Code + PlantUML Extension


This article describes the Tomcat with Tomcat-9.0.0.M22 as standard.

Tomcat-9.0.0.M22 Tomcat is the latest version, but not yet published, which implements Servlet4.0 and JSP2.3 and offers many new features, you need JDK 1.8 and above support, etc. For details, please refer to Tomcat- 9.0-doc

  • Overview

  • Connector Init and Start

  • Requtst Process

  • Acceptor

  • Poller

  • Worker

  • Container

  • At last

Overview

7316db14318b47b69a7d0c11eeaa3f79


  1. Connector starts after starting a set of threads used to request the different stages of the process.

  2. Acceptor thread group. For receiving a new connection, a new connection and packaging it, to select a new connection Poller Poller added to the event queue.

  3. Poller thread group. Socket to listen for events when Socket read or write and so on, will look to add to the package Socket worker thread pool task queue.

  4. worker thread group. It used to process the request, including an analysis of the request packet and create a Request object, calling the container pipeline for processing.

  • Acceptor, Poller, worker resides in NioEndpoint in ThreadPoolExecutor maintains.


Connector Init and Start

ea694d3b1f9543f29ca63343987274ed


  1. initServerSocket (), by ServerSocketChannel.open () to open the ServerSocket a default port 8080 is bound to, the default connection queue length is 100, when more than 100 when the service will be rejected. We can configure the Connector's conf / server.xml in acceptCount attributes to customize it.

  2. createExecutor() 用于创建 Worker 线程池。默认会启动 10 个 Worker 线程,Tomcat 处理请求过程中,Woker 最多不超过 200 个。我们可以通过配置 conf/server.xml 中 Connector 的 minSpareThreads 和 maxThreads 对这两个属性进行定制。

  3. Pollor 用于检测已就绪的 Socket。 默认最多不超过 2 个, Math.min(2,Runtime.getRuntime().availableProcessors());。我们可以通过配置 pollerThreadCount 来定制。

  4. Acceptor 用于接受新连接。默认是 1 个。我们可以通过配置 acceptorThreadCount 对其进行定制。

Requtst Process

Acceptor

2240ae4e641342ada5e99057ad35b6fb


  1. Acceptor 在启动后会阻塞在 ServerSocketChannel.accept(); 方法处,当有新连接到达时,该方法返回一个 SocketChannel。

  2. 配置完 Socket 以后将 Socket 封装到 NioChannel 中,并注册到 Poller, 值的一提的是,我们一开始就启动了多个 Poller 线程,注册的时候,连接是公平的分配到每个 Poller 的。 NioEndpoint 维护了一个 Poller 数组,当一个连接分配给 pollers[index] 时,下一个连接就会分配给 pollers[(index+1)%pollers.length].

  3. addEvent() 方法会将 Socket 添加到该 Poller 的 PollerEvent 队列中。到此 Acceptor 的任务就完成了。

Poller

ea0969d0e7a94ac5ab5f30cbbc317695


  1. selector.select(1000)。当 Poller 启动后因为 selector 中并没有已注册的 Channel,所以当执行到该方法时只能阻塞。所有的 Poller 共用一个 Selector,其实现类是 sun.nio.ch.EPollSelectorImpl

  2. events() 方法会将通过 addEvent() 方法添加到事件队列中的 Socket 注册到 EPollSelectorImpl,当 Socket 可读时, Poller 才对其进行处理

  3. createSocketProcessor() 方法将 Socket 封装到 SocketProcessor 中, SocketProcessor 实现了 Runnable 接口。 worker 线程通过调用其 run() 方法来对 Socket 进行处理。

  4. execute(SocketProcessor) 方法将 SocketProcessor 提交到线程池,放入线程池的 workQueue 中。 workQueue 是 BlockingQueue 的实例。到此 Poller 的任务就完成了。

Worker

4c8b818afbf94c6786ea07caee057feb


  1. worker 线程被创建以后就执行 ThreadPoolExecutor 的 runWorker() 方法,试图从 workQueue 中取待处理任务,但是一开始 workQueue 是空的,所以 worker 线程会阻塞在 workQueue.take() 方法。

  2. 当新任务添加到 workQueue后, workQueue.take() 方法会返回一个 Runnable,通常是 SocketProcessor, 然后 worker 线程调用 SocketProcessor 的 run() 方法对 Socket 进行处理。

  3. createProcessor() 会创建一个 Http11Processor, 它用来解析 Socket,将 Socket 中的内容封装到 Request 中。注意这个 Request 是临时使用的一个类,它的全类名是 org.apache.coyote.Request,

  4. postParseRequest() 方法封装一下 Request,并处理一下映射关系 (从 URL 映射到相应的 Host、 Context、 Wrapper)。

  5. CoyoteAdapter 将 Rquest 提交给 Container 处理之前,并将 org.apache.coyote.Request 封装到 org.apache.catalina.connector.Request,传递给 Container 处理的 Request 是 org.apache.catalina.connector.Request。

  6. connector.getService().getMapper().map(),用来在 Mapper 中查询 URL 的映射关系。映射关系会保留到 org.apache.catalina.connector.Request 中, Container 处理阶段 request.getHost() 是使用的就是这个阶段查询到的映射主机,以此类推 request.getContext()、 request.getWrapper() 都是。

  7. connector.getService().getContainer().getPipeline().getFirst().invoke() 会将请求传递到 Container 处理,当然了 Container 处理也是在 Worker 线程中执行的,但是这是一个相对独立的模块,所以单独分出来一节。

Container

5f471db318004e908f3e49ea280969fc


  1. Note that, basically StandardPipeline on each container will have more registered Valve, we are only concerned Basic Valve each container. Other Valve are executed before the Basic Valve.

  2. request.getHost (). getPipeline (). getFirst (). invoke () to acquire the corresponding StandardHost, and performs its pipeline.

  3. request.getContext (). getPipeline (). getFirst (). invoke () to acquire the corresponding StandardContext, and performs its pipeline.

  4. request.getWrapper (). getPipeline (). getFirst (). invoke () to acquire the corresponding StandardWrapper, and performs its pipeline.

  5. Most say is StandardWrapper of Basic Valve, StandardWrapperValve

  6. the allocate () is used to load and initialize the Servlet, mention Servlet value is not always a single embodiment, when the Servlet implements SingleThreadModel interface, StandardWrapper Servlet maintains a set of instances, which is Flyweight. Of course SingleThreadModel after abandoned the Servlet 2.4.

  7. createFilterChain () method will get from StandardContext in all filters, and then match all filters Request URL is added to the filterChain singled out in.

  8. the doFilter () performs filtering chain, when all the filters were completed Servlet invocation of service () method


Guess you like

Origin blog.51cto.com/14480698/2439003