標籤:tomcat jbossweb io socket
概述
JBossWeb 是JBoss 中的 Web 容器,他是對 Tomcat 的封裝,本文以 Http 連接器為例,簡單說明 JBossWeb/Tomcat 初始化連接器和處理 Http 請求過程 。本文內容提要:
- Connector 初始化開始過程
- 如何理解 max-connections
- JIoEndpoint 處理 Socket 請求
Connector 初始化開始過程
如所示:
- WebConnectorService 指的是 `org.jboss.as.web.WebConnectorService`
- Connector 指的是 `org.apache.catalina.connector.Connector`
- Http11Protocol 指的是 `org.apache.coyote.http11.Http11Protocol`
- JIoEndpoint 指的是 `org.apache.tomcat.util.net.JIoEndpoint`
Connector init()
Connector 可以是 HTTP Connector,也可以是 AJP Connector,Connector 中有 ProtocolHandler 和 Adapter 屬性,Connector 初始化主要包括:初始化 Adapter,且將初始化的 Adapter 的 設定給 ProtocolHandler,然後調運 ProtocolHandler 的初始化方法,如下面程式碼片段所示:
// Initializa adapter adapter = new CoyoteAdapter(this); protocolHandler.setAdapter(adapter); IntrospectionUtils.setProperty(protocolHandler, "jkHome", System.getProperty("catalina.base")); try { protocolHandler.init(); } catch (Exception e) { throw new LifecycleException(MESSAGES.protocolHandlerInitFailed(e)); }
Http11Protocol init()
Http11Protocol 它有一個 Http11ConnectionHandler Handler,該 Handler 實現 `org.apache.tomcat.util.net.JIoEndpoint.Handler` 介面,Http11Protocol 同樣有一個 JIoEndpoint 屬性,該屬性用來處理 incoming TCP connections,如下程式碼片段所示:
protected Http11ConnectionHandler cHandler = new Http11ConnectionHandler(this); protected JIoEndpoint endpoint = new JIoEndpoint();
Http11Protocol 初始化主要包括:
- 給 JIoEndpoint 設定名字,預設設定的名字為 http-/127.0.0.1:8080
- 給 JIoEndpoint 設定 socket handler,設定的 handler 為 Http11ConnectionHandler,該 handler 的作用是 Handling of accepted sockets
- 調運 JIoEndpoint 的初始化方法
JIoEndpoint init()
JIoEndpoint,關於此類的作用之前我們有說,對該類最直接的總結如下:
/** * Handle incoming TCP connections. * * This class implement a simple server model: one listener thread accepts on a socket and * creates a new worker thread for each incoming connection. * * More advanced Endpoints will reuse the threads, use queues, etc. * * @author James Duncan Davidson * @author Jason Hunter * @author James Todd * @author Costin Manolache * @author Gal Shachor * @author Yoav Shapira * @author Remy Maucherat */public class JIoEndpoint {
JIoEndpoint 初始化包括:
- 初始化 Acceptor thread count,預設初始設定的 Acceptor thread count 為 1
- 初始化 ServerSocketFactory,並通過初始化的 ServerSocketFactory 建立 ServerSocket
Connector start()
Connector 開始方法驗證更新當前的狀態,並調運 Http11Protocol 的開始方法
Http11Protocol start()
Http11Protocol 的開始方法中直接調運 JIoEndpoint 的開始方法。
JIoEndpoint start()
JIoEndpoint 的開始方法主要包括:
如果外部基於 Executor 的線程池為空白,則初始化內部的 workers 棧,該棧儲存Worker,初始化的棧大小定義如下:
protected int maxThreads = (org.apache.tomcat.util.Constants.LOW_MEMORY) ? 64 : ((Constants.MAX_THREADS == -1) ? 512 * Runtime.getRuntime().availableProcessors() : Constants.MAX_THREADS);
如上:
- 如果通過系統參數 -Dorg.apache.tomcat.util.LOW_MEMORY=true,則初始化的棧大小為 64
- 如果通過系統參數 -Dorg.apache.tomcat.util.net.MAX_THREADS=XXX 指定最大值,則初始化的棧大小為系統參數指定的最大值
- 如果沒有通過系統參數指定 MAX_THREADS,則初始化的棧大小為Runtime.getRuntime().availableProcessors()
啟動 Poller 線程,預設線程的名字為 http-/127.0.0.1:8080-Poller。
啟動 Acceptor 線程,預設線程的名字為 http-/127.0.0.1:8080-Acceptor-0
如下程式碼片段顯示如上邏輯
public void start() throws Exception { // Initialize socket if not done before if (!initialized) { init(); } if (!running) { running = true; paused = false; // Create worker collection if (executor == null) { workers = new WorkerStack(maxThreads); } // Start event poller thread eventPoller = new Poller(); eventPoller.init(); Thread pollerThread = new Thread(eventPoller, getName() + "-Poller"); pollerThread.setPriority(threadPriority); pollerThread.setDaemon(true); pollerThread.start(); // Start acceptor threads for (int i = 0; i < acceptorThreadCount; i++) { Thread acceptorThread = new Thread(new Acceptor(), getName() + "-Acceptor-" + i); acceptorThread.setPriority(threadPriority); acceptorThread.setDaemon(daemon); acceptorThread.start(); } } }
如何理解 max-connections
JBoss Web 中關於max-connections 的定義如下
<subsystem xmlns="urn:jboss:domain:web:1.4" default-virtual-server="default-host" native="false"> <connector name="http" protocol="HTTP/1.1" scheme="http" socket-binding="http" max-connections="200" />
如上,如果我們定義了 max-connections,WebConnectorService 開始方法中會有如下邏輯:
- 設定 JIoEndpoint 中 pollerSize,如下代碼:
protected int pollerSize = (org.apache.tomcat.util.Constants.LOW_MEMORY) ? 128 : (32 * 1024); public void setPollerSize(int pollerSize) { this.pollerSize = pollerSize; } public int getPollerSize() { return pollerSize; }
如上,預設的 pollerSize 如果沒有 -Dorg.apache.tomcat.util.LOW_MEMORY=true 設定,它的值為 32 * 1024。
- 設定 JIoEndpoint 中 maxThreads,如下程式碼片段:
protected int maxThreads = (org.apache.tomcat.util.Constants.LOW_MEMORY) ? 64 : ((Constants.MAX_THREADS == -1) ? 512 * Runtime.getRuntime().availableProcessors() : Constants.MAX_THREADS); public void setMaxThreads(int maxThreads) { this.maxThreads = maxThreads; } public int getMaxThreads() { return maxThreads; }
注意,該 maxThreads 用來初始化內部的 workers 棧的大小。
JIoEndpoint 處理 Socket 請求
JIoEndpoint 處理 Socket 請求如所示
如上,首先 Acceptor 線程(通常名字為 http-/127.0.0.1:8080-Acceptor-0)阻塞等待 Socket 串連,如下所示:
"http-/127.0.0.1:8080-Acceptor-0" daemon prio=10 tid=0x49ed5800 nid=0xbe9 runnable [0x49789000] java.lang.Thread.State: RUNNABLE at java.net.PlainSocketImpl.socketAccept(Native Method) at java.net.AbstractPlainSocketImpl.accept(AbstractPlainSocketImpl.java:398) at java.net.ServerSocket.implAccept(ServerSocket.java:522) at java.net.ServerSocket.accept(ServerSocket.java:490) at org.apache.tomcat.util.net.DefaultServerSocketFactory.acceptSocket(DefaultServerSocketFactory.java:61) at org.apache.tomcat.util.net.JIoEndpoint$Acceptor.run(JIoEndpoint.java:309) at java.lang.Thread.run(Thread.java:722) Locked ownable synchronizers: - None
//coming soon