Spring Boot Tomcat 架构及参数优化

1. Springboot Tomcat 架构及参数优化

1.1. 版本说明

构件 版本
spring-boot 2.7.18
tomcat-embed-core 9.0.83

1.2. SpringBoot Tomcat 架构分析

1.2.1. Tomcat 核心组件类图

1
1
1
1
1
1
1
1
1
1
1
1
n
1
n
1
1
1
1
1

Tomcat

#Server server

+void start()

+void stop()

Connector

#ProtocolHandler protocolHandler

«Interface»

Container

«Interface»

Engine

StandardEngine

«Interface»

Host

StandardHost

«Interface»

Lifecycle

void start()

void stop()

«Interface»

Server

StandardServer

-Service[] services

«Interface»

Service

StandardService

#Connector[] connectors

-Engine engine

AbstractHttp11JsseProtocol<S>

AbstractHttp11Protocol<S>

AbstractProtocol<S>

-AbstractEndpoint endpoint

Http11NioProtocol

Http11Nio2Protocol

«Interface»

ProtocolHandler

void start()

void stop()

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()

AbstractJsseEndpoint<S, U>

Nio2Endpoint

NioEndpoint

-ServerSocketChannel serverSock

«Interface»

Executor

ThreadPoolExecutor

VirtualThreadExecutor

LimitLatch

-AtomicLong count

-long limit

+long countDown()

+void countUpOrAwait()

«Interface»

Handler

ConnectionHandler<S>

Poller

Acceptor

SocketProcessor

SocketProcessorBase<S>

«Interface»

Runnable

Tomcat 线程池在 AbstractEndpoint 创建,server.tomcat.threads.max、\n server.tomcat.threads.min-spare 参数作用于此,\n 用于指定最大、最小线程数,线程池其他参数默认值为:\n 是否守护线程:是;\n 线程优先级:5;\n 空闲线程存活时间:60 秒;\n 任务队列为:TaskQueue,容量为 Integer.MAX_VALUE

LimitLatch 用于限制连接数量,基于 AQS 实现,\n server.tomcat.max-connections 参数作用于此,\n 接受一个连接前判断是否达到最大连接数 limit,\n 否则自旋等待直至成功并 count 加 1;\n 关闭连接后 count 减 1

Poller 线程不停从已连接的 socket 读取事件,\n 最终封装成 SocketProcessorBase 交给 ThreadPoolExecutor 处理

Acceptor 线程不停接收新的客户端连接,\n 直至达到 server.tomcat.max-connections

SocketProcessorBase 线程将请求经过层层传递最终给到\n DispatcherServlet,DispatcherServlet 再分派到对应的\n Spring Controller 中处理具体的业务逻辑

1.2.2. Tomcat 核心组件架构图

1.3. SpringBoot Tomcat 工作流程

1.3.1. SpringBoot 初始化 Tomcat 流程

TomcatServletWebServerFactory#getWebServer(ServletContextInitializer... initializers)

Tomcat#Tomcat()

Tomcat#start()

SpringApplication#run(Class primarySource, String... args)

SpringApplication#run(Class[] primarySources, String[] args)

SpringApplication#run(String... args)

SpringApplication#refreshContext(ConfigurableApplicationContext context)

SpringApplication#refresh(ConfigurableApplicationContext applicationContext)

ServletWebServerApplicationContext#refresh()

AbstractApplicationContext#refresh()

ServletWebServerApplicationContext#onRefresh()

ServletWebServerApplicationContext#createWebServer()

1.3.2. Tomcat 启动流程

NioEndpoint#start()

Tomcat#start()

StandardServer#start()

StandardService#start()

StandardEngine#start()

Connector#start()

Http11NioProtocol#start()

NioEndpoint#bind() \n 初始化 ServerSocketChannel,绑定端口

NioEndpoint#createExecutor() \n 创建工作线程池

NioEndpoint#initializeConnectionLatch() \n 初始化限流组件

Poller#Poller() \n 启动 socket 事件监听线程

Acceptor#Acceptor() \n 启动 socket 连接线程

1.3.2.1. 初始化 ServerSocketChannel

核心源码:

serverSock = ServerSocketChannel.open();
InetSocketAddress addr = new InetSocketAddress(getAddress(), getPortWithOffset());
serverSock.bind(addr, getAcceptCount());
  1. 打开 ServerSocketChannel。
  2. 绑定端口,指定 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);
  1. TaskQueue 任务队列继承自 LinkedBlockingQueue,这里无法指定容量,默认容量为 Integer.MAX_VALUE,即无限大。预计未来将支持指定容量,详见 github issues
  2. TaskThreadFactory 线程工厂指定了线程名称前缀为 http-nio-端口-;线程为守护线程;线程优先级为默认值:5。
  3. 线程池核心线程数由 server.tomcat.threads.min-spare 配置参数指定,默认值为 10;线程池最大线程数由 server.tomcat.threads.max 配置参数指定,默认值为 200;空闲线程存活时间 60 秒。

TaskQueue 重写了 offer 方法,使得 Tomcat 线程池与 JDK 线程池创建线程的时机不一样,具体表现为:

  1. 如果线程池里的线程数量等于最大线程数,说明无法再创建新线程,任务加入队列中,等待空闲线程处理。
  2. 如果已提交的任务数小于等于线程池里的线程数量,说明有空闲线程,任务加入队列中,由空闲线程处理。
  3. 如果线程池里的线程数量小于最大线程数,任务无法加入队列,强制线程池新建线程去处理。
  4. 如果以上都不是,任务加入队列,等待空闲线程处理。

核心源码:

@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 线程工作流程

no

no \n 自旋-等待-重试

yes

线程启动

停止?

尝试 LimitLatch 计数加 1

成功?

SocketChannel socket = endpoint.serverSocketAccept() \n 接收新连接

SocketChannel 封装为 NioSocketWrapper

NioSocketWrapper 封装为 PollerEvent

PollerEvent 注册到 Poller 的 SynchronizedQueue 队列,Poller 线程处理队列里的事件

1.3.4. Poller 线程工作流程

yes

线程启动

while(true)

Poller#events() \n 处理 SynchronizedQueue 队列里的 PollerEvent 事件

Selector#selectedKeys() \n 监听 socket 事件

Poller#processKey(SelectionKey sk, NioSocketWrapper socketWrapper) \n 处理监听到的事件

AbstractEndpoint#processSocket(SocketWrapperBase socketWrapper, SocketEvent event, boolean dispatch) \n 封装 SocketProcessor 多线程任务,提交到线程池处理

1.3.5. SocketProcessor 线程处理请求工作流程

Wrapper

Context

Host

Connector

Pipeline

Pipeline

Pipeline

Service

Engine

Pipeline

NioSocketWrapper

NioSocketWrapper

Request, Response

Request, Response

Request, Response

Request, Response

Request, Response

ServletRequest, ServletResponse

ServletRequest, ServletResponse

ServletRequest, ServletResponse, HandlerMethod

SocketProcessor#doRun()

ConnectionHandler#process(SocketWrapperBase socket, SocketEvent status)

Http11Processor#process(SocketWrapperBase socketWrapper, SocketEvent status)

CoyoteAdapter#service(Request req, Response res)

StandardEngineValve#invoke(Request request, Response response)

StandardHostValve#invoke(Request request, Response response)

StandardContextValve#invoke(Request request, Response response)

StandardWrapperValve#invoke(Request request, Response response)

FilterChain#doFilter(ServletRequest request, ServletResponse response)

DispatcherServlet#service(ServletRequest req, ServletResponse res)

RequestMappingHandlerAdapter#handle(HttpServletRequest request, HttpServletResponse response, Object handler)

ServletInvocableHandlerMethod#(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs)

Spring Web Controller 层,处理具体业务

1.4. 配置参数优化

1.4.1. Tomcat 相关 Server Properties

  • server.tomcat.accept-count: Maximum queue length for incoming connection requests when all possible request processing threads are in use. default: 100.
  • server.tomcat.accesslog.buffered: Whether to buffer output such that it is flushed only periodically. default: true.
  • server.tomcat.accesslog.check-exists: Whether to check for log file existence so it can be recreated if an external process has renamed it. default: false.
  • server.tomcat.accesslog.condition-if: Whether logging of the request will only be enabled if "ServletRequest.getAttribute(conditionIf)" does not yield null.
  • server.tomcat.accesslog.condition-unless: Whether logging of the request will only be enabled if "ServletRequest.getAttribute(conditionUnless)" yield null.
  • server.tomcat.accesslog.directory: Directory in which log files are created. Can be absolute or relative to the Tomcat base dir. default: logs.
  • server.tomcat.accesslog.enabled: Enable access log. default: false.
  • server.tomcat.accesslog.encoding: Character set used by the log file. Default to the system default character set.
  • server.tomcat.accesslog.file-date-format: Date format to place in the log file name. default: .yyyy-MM-dd.
  • server.tomcat.accesslog.ipv6-canonical: Whether to use IPv6 canonical representation format as defined by RFC 5952. default: false.
  • server.tomcat.accesslog.locale: Locale used to format timestamps in log entries and in log file name suffix. Default to the default locale of the Java process.
  • server.tomcat.accesslog.max-days: Number of days to retain the access log files before they are removed. default: -1.
  • server.tomcat.accesslog.pattern: Format pattern for access logs. default: common.
  • server.tomcat.accesslog.prefix: Log file name prefix. default: access_log.
  • server.tomcat.accesslog.rename-on-rotate: Whether to defer inclusion of the date stamp in the file name until rotate time. default: false.
  • server.tomcat.accesslog.request-attributes-enabled: Set request attributes for the IP address, Hostname, protocol, and port used for the request. default: false.
  • server.tomcat.accesslog.rotate: Whether to enable access log rotation. default: true.
  • server.tomcat.accesslog.suffix: Log file name suffix. default: .log.
  • server.tomcat.additional-tld-skip-patterns: Comma-separated list of additional patterns that match jars to ignore for TLD scanning. The special '?' and '*' characters can be used in the pattern to match one and only one character and zero or more characters respectively.
  • server.tomcat.background-processor-delay: Delay between the invocation of backgroundProcess methods. If a duration suffix is not specified, seconds will be used. default: 10s.
  • server.tomcat.basedir: Tomcat base directory. If not specified, a temporary directory is used.
  • server.tomcat.connection-timeout: Amount of time the connector will wait, after accepting a connection, for the request URI line to be presented.
  • server.tomcat.keep-alive-timeout: Time to wait for another HTTP request before the connection is closed. When not set the connectionTimeout is used. When set to -1 there will be no timeout.
  • server.tomcat.max-connections: Maximum number of connections that the server accepts and processes at any given time. Once the limit has been reached, the operating system may still accept connections based on the "acceptCount" property. default: 8192.
  • server.tomcat.max-http-form-post-size: Maximum size of the form content in any HTTP post request. default: 2MB.
  • server.tomcat.max-keep-alive-requests: Maximum number of HTTP requests that can be pipelined before the connection is closed. When set to 0 or 1, keep-alive and pipelining are disabled. When set to -1, an unlimited number of pipelined or keep-alive requests are allowed. default: 100.
  • server.tomcat.max-swallow-size: Maximum amount of request body to swallow. default: 2MB.
  • server.tomcat.mbeanregistry.enabled: Whether Tomcat's MBean Registry should be enabled. default: false.
  • server.tomcat.processor-cache: Maximum number of idle processors that will be retained in the cache and reused with a subsequent request. When set to -1 the cache will be unlimited with a theoretical maximum size equal to the maximum number of connections. default: 200.
  • server.tomcat.redirect-context-root: Whether requests to the context root should be redirected by appending a / to the path. When using SSL terminated at a proxy, this property should be set to false. default: true.
  • server.tomcat.relaxed-path-chars: Comma-separated list of additional unencoded characters that should be allowed in URI paths. Only "< > [ \ ] ^ ` { | }" are allowed.
  • server.tomcat.relaxed-query-chars: Comma-separated list of additional unencoded characters that should be allowed in URI query strings. Only "< > [ \ ] ^ ` { | }" are allowed.
  • server.tomcat.remoteip.host-header: Name of the HTTP header from which the remote host is extracted. default: X-Forwarded-Host.
  • server.tomcat.remoteip.internal-proxies: Regular expression that matches proxies that are to be trusted. default: 10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|192\\.168\\.\\d{1,3}\\.\\d{1,3}|169\\.254\\.\\d{1,3}\\.\\d{1,3}|127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|100\\.6[4-9]{1}\\.\\d{1,3}\\.\\d{1,3}|100\\.[7-9]{1}\\d{1}\\.\\d{1,3}\\.\\d{1,3}|100\\.1[0-1]{1}\\d{1}\\.\\d{1,3}\\.\\d{1,3}|100\\.12[0-7]{1}\\.\\d{1,3}\\.\\d{1,3}|172\\.1[6-9]{1}\\.\\d{1,3}\\.\\d{1,3}|172\\.2[0-9]{1}\\.\\d{1,3}\\.\\d{1,3}|172\\.3[0-1]{1}\\.\\d{1,3}\\.\\d{1,3}|0:0:0:0:0:0:0:1|::1.
  • server.tomcat.remoteip.port-header: Name of the HTTP header used to override the original port value. default: X-Forwarded-Port.
  • server.tomcat.remoteip.protocol-header: Header that holds the incoming protocol, usually named "X-Forwarded-Proto".
  • server.tomcat.remoteip.protocol-header-https-value: Value of the protocol header indicating whether the incoming request uses SSL. default: https.
  • server.tomcat.remoteip.remote-ip-header: Name of the HTTP header from which the remote IP is extracted. For instance, 'X-FORWARDED-FOR'.
  • server.tomcat.resource.allow-caching: Whether static resource caching is permitted for this web application. default: true.
  • server.tomcat.resource.cache-ttl: Time-to-live of the static resource cache.
  • server.tomcat.threads.max: Maximum amount of worker threads. default: 200.
  • server.tomcat.threads.min-spare: Minimum amount of worker threads. default: 10.
  • server.tomcat.uri-encoding: Character encoding to use to decode the URI. default: UTF-8.
  • server.tomcat.use-relative-redirects: Whether HTTP 1.1 and later location headers generated by a call to sendRedirect will use relative or absolute redirects. default: false.

1.4.2. 参考配置

服务器配置:

CPU 核心 内存
4 核 8G
server:
tomcat:
threads:
max: 1000
min-spare: 200
accept-count: 1000
max-connections: 10000
posted @   Jason207010  阅读(837)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示