1. Springboot Tomcat 架構及參數優化
1.1. 版本説明
| 構件 |
版本 |
| spring-boot |
2.7.18 |
| tomcat-embed-core |
9.0.83 |
1.2. SpringBoot Tomcat 架構分析
1.2.1. Tomcat 核心組件類圖
classDiagram
direction LR
class Tomcat {
#Server server
+void start()
+void stop()
}
class Connector {
#ProtocolHandler protocolHandler
}
class Container {
<<Interface>>
}
class Engine {
<<Interface>>
}
class StandardEngine
class Host {
<<Interface>>
}
class StandardHost
class Lifecycle {
<<Interface>>
void start()
void stop()
}
class Server {
<<Interface>>
}
class StandardServer {
-Service[] services
}
class Service {
<<Interface>>
}
class StandardService {
#Connector[] connectors
-Engine engine
}
class AbstractHttp11JsseProtocol~S~
class AbstractHttp11Protocol~S~
class AbstractProtocol~S~ {
-AbstractEndpoint endpoint
}
class Http11NioProtocol
class Http11Nio2Protocol
class ProtocolHandler {
<<Interface>>
void start()
void stop()
}
class AbstractEndpoint~S, U~ {
-Executor executor
-LimitLatch connectionLimitLatch
-Handler~S~ handler
+void bind()
#U serverSocketAccept()
+void createExecutor()
+boolean processSocket(SocketWrapperBase~S~> socketWrapper, SocketEvent event, boolean dispatch)
+void start()
+void stop()
}
class AbstractJsseEndpoint~S, U~
class Nio2Endpoint
class NioEndpoint {
-ServerSocketChannel serverSock
}
class Executor {
<<Interface>>
}
class ThreadPoolExecutor
class VirtualThreadExecutor
class LimitLatch {
-AtomicLong count
-long limit
+long countDown()
+void countUpOrAwait()
}
class Handler {
<<Interface>>
}
class ConnectionHandler~S~
class Poller
class Acceptor
class SocketProcessor
class SocketProcessorBase~S~
class Runnable {
<<Interface>>
}
Tomcat "1" *--> "1" Host
Tomcat "1" *--> "1" Server
Host --|> Container
StandardHost ..|> Host
StandardServer ..|> Server
StandardServer "1" *--> "n" Service
Server --|> Lifecycle
Service --|> Lifecycle
StandardService ..|> Service
StandardService "1" *--> "1" Engine
StandardService "1" *--> "n" Connector
StandardEngine ..|> Engine
Engine --|> Container
Container --|> Lifecycle
Connector ..|> Lifecycle
Connector "1" *--> "1" ProtocolHandler
Http11NioProtocol --|> AbstractHttp11JsseProtocol
Http11Nio2Protocol --|> AbstractHttp11JsseProtocol
AbstractHttp11JsseProtocol --|> AbstractHttp11Protocol
AbstractHttp11Protocol --|> AbstractProtocol
AbstractProtocol ..|> ProtocolHandler
AbstractProtocol "1" *--> "1" AbstractEndpoint
AbstractJsseEndpoint --|> AbstractEndpoint
Nio2Endpoint --|> AbstractJsseEndpoint
NioEndpoint --|> AbstractJsseEndpoint
AbstractEndpoint "1" *--> "1" Executor
AbstractEndpoint "1" *--> "1" LimitLatch
AbstractEndpoint "1" *--> "1" Handler
AbstractEndpoint ..> SocketProcessorBase
ThreadPoolExecutor ..|> Executor
VirtualThreadExecutor ..|> Executor
ConnectionHandler ..|> Handler
Poller ..|> Runnable
Acceptor ..|> Runnable
Poller ..> AbstractEndpoint
Acceptor ..> AbstractEndpoint
SocketProcessor --|> SocketProcessorBase~S~
SocketProcessorBase~S~ ..|> Runnable
- Tomcat 線程池在 AbstractEndpoint 創建,server.tomcat.threads.max、server.tomcat.threads.min-spare 參數作用於此,用於指定最大、最小線程數,線程池其他參數默認值為:是否守護線程:是;線程優先級:5;空閒線程存活時間:60 秒;任務隊列為:TaskQueue,容量為 Integer.MAX_VALUE
- LimitLatch 用於限制連接數量,基於 AQS 實現,server.tomcat.max-connections 參數作用於此,接受一個連接前判斷是否達到最大連接數 limit,否則自旋等待直至成功並 count 加 1;關閉連接後 count 減 1
- Poller 線程不停從已連接的 socket 讀取事件,最終封裝成 SocketProcessorBase 交給 ThreadPoolExecutor 處理
- Acceptor 線程不停接收新的客户端連接,直至達到 server.tomcat.max-connections
- SocketProcessorBase 線程將請求經過層層傳遞最終給到DispatcherServlet,DispatcherServlet 再分派到對應的Spring Controller 中處理具體的業務邏輯
1.2.2. Tomcat 核心組件架構圖

1.3. SpringBoot Tomcat 工作流程
1.3.1. SpringBoot 初始化 Tomcat 流程
flowchart TD
flow1("SpringApplication#run(Class<?> primarySource, String... args)") --> flow2("SpringApplication#run(Class<?>[] primarySources, String[] args)")
flow2 --> flow3("SpringApplication#run(String... args)")
flow3 --> flow4("SpringApplication#refreshContext(ConfigurableApplicationContext context)")
flow4 --> flow5("SpringApplication#refresh(ConfigurableApplicationContext applicationContext)")
flow5 --> flow6("ServletWebServerApplicationContext#refresh()")
flow6 --> flow7("AbstractApplicationContext#refresh()")
flow7 --> flow8("ServletWebServerApplicationContext#onRefresh()")
flow8 --> flow9("ServletWebServerApplicationContext#createWebServer()")
subgraph flow10["TomcatServletWebServerFactory#getWebServer(ServletContextInitializer... initializers)"]
direction LR
flow10_1("Tomcat#Tomcat()")
flow10_1 --> flow10_2("Tomcat#start()")
end
flow9 --> flow10
1.3.2. Tomcat 啓動流程
flowchart TD
flow1["Tomcat#start()"]
flow2["StandardServer#start()"]
flow3["StandardService#start()"]
flow4["StandardEngine#start()"]
flow5["Connector#start()"]
flow6["Http11NioProtocol#start()"]
subgraph flow7["NioEndpoint#start()"]
flow8["NioEndpoint#bind() \n 初始化 ServerSocketChannel,綁定端口"]
flow9["NioEndpoint#createExecutor() \n 創建工作線程池"]
flow10["NioEndpoint#initializeConnectionLatch() \n 初始化限流組件"]
flow11["Poller#Poller() \n 啓動 socket 事件監聽線程"]
flow12["Acceptor#Acceptor() \n 啓動 socket 連接線程"]
end
flow1 --> flow2
flow2 --> flow3
flow3 --> flow4
flow3 --> flow5
flow5 --> flow6
flow6 --> flow7
flow7 --> flow8
flow8 --> flow9
flow9 --> flow10
flow10 --> flow11
flow11 --> flow12
1.3.2.1. 初始化 ServerSocketChannel
核心源碼:
serverSock = ServerSocketChannel.open();
InetSocketAddress addr = new InetSocketAddress(getAddress(), getPortWithOffset());
serverSock.bind(addr, getAcceptCount());
- 打開 ServerSocketChannel。
- 綁定端口,指定 backlog
其中端口由 server.port 配置參數指定,backlog 由 server.tomcat.accept-count 配置參數指定,默認值為 100,客户端與服務端完成 TCP 三次握手之後,連接放入等待隊列中,ServerSocketChannel 調用 accept() 方法從隊列中取出連接。因此,當 Tomcat 達到 max-connections 指定的最大連接數後,還能繼續接收 accept-count 數量的連接。
1.3.2.2. 初始化工作線程池
核心源碼:
TaskQueue taskqueue = new TaskQueue();
TaskThreadFactory tf = new TaskThreadFactory(getName() + "-exec-", daemon, getThreadPriority());
executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf);
taskqueue.setParent( (ThreadPoolExecutor) executor);
TaskQueue 任務隊列繼承自 LinkedBlockingQueue,這裏無法指定容量,默認容量為 Integer.MAX_VALUE,即無限大。預計未來將支持指定容量,詳見 github issues。
TaskThreadFactory 線程工廠指定了線程名稱前綴為 http-nio-端口-;線程為守護線程;線程優先級為默認值:5。
- 線程池核心線程數由
server.tomcat.threads.min-spare 配置參數指定,默認值為 10;線程池最大線程數由 server.tomcat.threads.max 配置參數指定,默認值為 200;空閒線程存活時間 60 秒。
TaskQueue 重寫了 offer 方法,使得 Tomcat 線程池與 JDK 線程池創建線程的時機不一樣,具體表現為:
- 如果線程池裏的線程數量等於最大線程數,説明無法再創建新線程,任務加入隊列中,等待空閒線程處理。
- 如果已提交的任務數小於等於線程池裏的線程數量,説明有空閒線程,任務加入隊列中,由空閒線程處理。
- 如果線程池裏的線程數量小於最大線程數,任務無法加入隊列,強制線程池新建線程去處理。
- 如果以上都不是,任務加入隊列,等待空閒線程處理。
核心源碼:
@Override
public boolean offer(Runnable o) {
//we can't do any checks
if (parent==null) {
return super.offer(o);
}
//we are maxed out on threads, simply queue the object
if (parent.getPoolSizeNoLock() == parent.getMaximumPoolSize()) {
return super.offer(o);
}
//we have idle threads, just add it to the queue
if (parent.getSubmittedCount() <= parent.getPoolSizeNoLock()) {
return super.offer(o);
}
//if we have less threads than maximum force creation of a new thread
if (parent.getPoolSizeNoLock() < parent.getMaximumPoolSize()) {
return false;
}
//if we reached here, we need to add it to the queue
return super.offer(o);
}
1.3.2.3. 初始化限流組件 LimitLatch
核心源碼:
protected LimitLatch initializeConnectionLatch() {
if (maxConnections==-1) {
return null;
}
if (connectionLimitLatch==null) {
connectionLimitLatch = new LimitLatch(getMaxConnections());
}
return connectionLimitLatch;
}
最大連接數由 server.tomcat.max-connections 配置參數指定,默認值為 8192,表示同一時間 Tomcat 能夠接受的最大連接數量。接受一個新連接 LimitLatch 計數加 1,處理完請求斷開連接,LimitLatch 計數減 1。
1.3.3. Acceptor 線程工作流程
flowchart TD
flow1["線程啓動"]
flow2{"停止?"}
flow3["嘗試 LimitLatch 計數加 1"]
flow4{"成功?"}
flow6["SocketChannel socket = endpoint.serverSocketAccept() \n 接收新連接"]
flow7["SocketChannel 封裝為 NioSocketWrapper"]
flow8["NioSocketWrapper 封裝為 PollerEvent"]
flow9["PollerEvent 註冊到 Poller 的 SynchronizedQueue 隊列,Poller 線程處理隊列裏的事件"]
flow1 --> flow2
flow2 --> |no|flow3
flow3 --> flow4
flow4 --> |no \n 自旋-等待-重試|flow3
flow4 --> |yes|flow6
flow6 --> flow7
flow7 --> flow8
flow8 --> flow9
flow9 --> flow2
1.3.4. Poller 線程工作流程
flowchart TD
flow1["線程啓動"]
flow2{"while(true)"}
flow3["Poller#events() \n 處理 SynchronizedQueue 隊列裏的 PollerEvent 事件"]
flow4["Selector#selectedKeys() \n 監聽 socket 事件"]
flow5["Poller#processKey(SelectionKey sk, NioSocketWrapper socketWrapper) \n 處理監聽到的事件"]
flow6["AbstractEndpoint#processSocket(SocketWrapperBase socketWrapper, SocketEvent event, boolean dispatch) \n 封裝 SocketProcessor 多線程任務,提交到線程池處理"]
flow1 --> flow2
flow2 --> |yes|flow3
flow3 --> flow4
flow4 --> flow5
flow5 --> flow6
flow6 --> flow2
SocketProcessor 線程處理請求工作流程
flowchart TD
flow1["SocketProcessor#doRun()"]
flow2["ConnectionHandler#process(SocketWrapperBase socket, SocketEvent status)"]
flow3["Http11Processor#process(SocketWrapperBase socketWrapper, SocketEvent status)"]
flow4["CoyoteAdapter#service(Request req, Response res)"]
subgraph subgraph1["Connector"]
subgraph subgraph1_1["Service"]
subgraph subgraph1_1_1["Engine"]
subgraph subgraph1_1_1_1["Pipeline"]
flow5["StandardEngineValve#invoke(Request request, Response response)"]
end
end
end
end
subgraph subgraph2["Host"]
subgraph subgraph 2_1["Pipeline"]
flow6["StandardHostValve#invoke(Request request, Response response)"]
end
end
subgraph subgraph3["Context"]
subgraph subgraph 3_1["Pipeline"]
flow7["StandardContextValve#invoke(Request request, Response response)"]
end
end
subgraph subgraph4["Wrapper"]
subgraph subgraph 4_1["Pipeline"]
flow8["StandardWrapperValve#invoke(Request request, Response response)"]
end
end
flow9["FilterChain#doFilter(ServletRequest request, ServletResponse response)"]
flow10["DispatcherServlet#service(ServletRequest req, ServletResponse res)"]
flow11["RequestMappingHandlerAdapter#handle(HttpServletRequest request, HttpServletResponse response, Object handler)"]
flow12["ServletInvocableHandlerMethod#(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs)"]
flow13["Controller 層,處理具體業務"]
flow1 -->|NioSocketWrapper| flow2
flow2 -->|NioSocketWrapper| flow3
flow3 -->|Request, Response| flow4
flow4 -->|Request, Response| flow5
flow5 -->|Request, Response| flow6
flow6 -->|Request, Response| flow7
flow7 -->|Request, Response| flow8
flow8 -->|ServletRequest, ServletResponse| flow9
flow9 -->|ServletRequest, ServletResponse| flow10
flow10 -->|ServletRequest, ServletResponse, HandlerMethod| flow11
flow11 --> flow12
flow12 --> flow13
1.4. 配置參數優化
服務器配置:
server:
tomcat:
threads:
max: 1000
min-spare: 200
accept-count: 1000
max-connections: 10000