Tomcat(五):Tomcat 参数调优教程
TIPS
本文基于 Tomcat 9.0 编写,理论兼容 Tomcat 8.x 及更高版本。
本文来探讨 Tomcat 的调优。
系统性能的衡量指标,主要是响应时间和吞吐量。
- 响应时间: 执行某个操作的耗时;
- 吞吐量: 系统在给定时间内能够⽀持的事务数量,单位为 TPS(Transactions PerSecond 的缩写,也就是事务数/秒,⼀个事务是指⼀个客户机向服务器发送请求然后服务器做出反应的过程。
Tomcat 优化从两个方⾯进行
- Tomcat ⾃身配置的优化(⽐如是否使⽤了共享线程池?IO 模型?)
- JVM 虚拟机优化(优化内存模型)
# 1. Tomcat 调优参数
# 1.1 主要调优参数
在做 Tomcat 的调优时,最重要是就是 Connector(连接器)的调优了(少数情况下,也可能会配置 Executor)
下面贴出一段 server.xml 中的配置:
<Executor name="tomcatThreadPool"
namePrefix="catalina-exec-"
maxThreads="150"
minSpareThreads="4"/>
<Connector port="8080"
protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
executor="tomcatThreadPool"/>
2
3
4
5
6
7
8
9
10
一个文件中可以有多个 Connector 以及多个 Executor。
其中:
Connector:负责接收客户端的请求以及向客户端回送响应的消息
Executor:指定线程池,从而在多个 Connector(主要)及其他组件之间共享
# 1.2 Connector 常用属性
Connector 负责接收客户端的请求以及向客户端回送响应的消息。Tomcat 9.0 有三类 Connector:
HTTP/1.1(HTTP Connector)
HTTP/2(HTTP2 Upgrade Protocol)(Tomcat 8.5 引入)
AJP(AJP Connector)
但不管哪种 Connector,工作过程都是类似的:
每个请求都需要 1 个线程去处理
如果接收到的并发请求 > 当前处理请求的线程所能处理的数量,则创建其他线程去处理,直到达到 maxThreads 为止
如果线程数达到 maxThreads 设置的值后,依然接收到更多的请求,那么请求将会堆积在 Connector 创建的 server socket 中(即 accept 队列),直到达到 acceptCount 的值为止。如果堆积的请求数目达到 acceptCount 后,依然受到更多的请求,那么直接返回 connection refused
常用属性如下:
TIPS
加粗的表示 Tomcat 调优常用的参数
这里只列出了 Connector 常用属性,要想阅读完整属性,可使用如下方式:
方式一、访问 http://tomcat.apache.org/tomcat-9.0-doc/config/http.html[2] ,将 9.0 修改为你的 Tomcat 版本即可,比如想看 Tomcat 8 的文档,可将 9.0 改为 8.0;
方式二、下载 Tomcat 并启动,访问
/docs/config/http.html
路径即可。例如:http://localhost:8080/docs/config/http.html
minSpareThreads:始终保持运行状态的线程数,默认值 10。即便超过了最大空闲时间(maxIdleTime),也不会被回收。如果配置了 Executor,将忽略此属性
maxThreads:Connector 创建来处理请求的最大线程数,此参数决定了可以同时处理的请求的最大数量,默认 200。如果配置了 Executor,将忽略此属性。超过则放入请求队列中进行排队。
maxConnections:Tomcat 在任意时间接收和处理的最大连接数。当连接数达到 maxConnections 时,仍可基于 acceptCount 的配置接受连接,但并不会处理,直到 Tomcat 接收的连接数小于 maxConnections。
默认值与 Connector 使用的协议有关:
- NIO 的默认值是 10000
- APR 的默认值是 8192
- BIO 的默认值为 maxThreads(如果配置了 Executor,则默认值是 Executor 的 maxThreads)
- 在 Windows 下,APR/native 的 maxConnections 值会自动调整为设置值以下最大的 1024 的整数倍;如设置为 2000,则最大值实际是 1024。如果设置为-1,则连接数不受限制。
connectionTimeout:网络连接超时时间,单位毫秒,默认 60000。设为 0 表示永不超时,一般不建议。除非将 disableUploadTimeout 设置为 false,否则读取 request body 时也会使用该超时。
acceptCount:当最大线程数(maxThreads)被使用完时,可以放入请求队列的队列长度,默认 100。一旦队列满了,就会返回 connection refused。因此,如果设置过大,后面进入的请求等待时间会很长;如果设置过小,后面进入的请求立马返回 connection refused。一般可设置成和 maxThreads 相同,但具体还需根据自己的应用实际访问峰值和平均值来权衡。
enableLookups:是否启用 DNS 查找功能。如果设为 true,会用 request.getRemoteHost()执行 DNS lookup,从而返回远程客户端的主机名。设为 false 则跳过 DNS lookup,并以字符串形式返回 IP 地址,从而提高性能,默认 false,生产环境建议保持关闭。
compression:是否开启 GZIP 压缩。取值 off(禁用)、on(打开,压缩文本数据),force(强制压缩所有格式)、数字(表示数据量达到该值就 GZIP 传输)。
port:指定 Tomcat 监听的端口
protocol:为 Connector 设置使用什么协议处理入口流量,默认值
HTTP/1.1
,使用此值的话,对于 Tomcat 8 及更高版本,会自动根据当前情况,使用基于 NIOConnector 或基于 APR 的 Connector;对 Tomcat 7 及更低版本会自动根据情况使用基于 BIO 的 Connector 或基于 APR 的 Connector。如果不想自动切换,也可人工指定协议(从 Tomcat 8 开始,一般无需人工设置):
/ BIO,这种模式下,使用传统的I/O操作(即java.io包及其子包),性能较差。
protocol="org.apache.coyote.http11.Http11Protocol"
// NIO,使用NIO操作(即java.nio包及其子包),比传统I/O拥有更好的并发性能
protocol="org.apache.coyote.http11.Http11NioProtocol"
// NIO2,使用NIO2操作(NIO2是JDK 7引入的特性),Tomcat 8引入
protocol="org.apache.coyote.http11.Http11Nio2Protocol"
// APR,使用APR操作。APR即Apache Portable Runtime,这是一个Apache HTTP服务器的支持库。你可以认为:此模式下,Tomcat将以JNI的形式调用 Apache HTTP服务器的核心动态链接库来处理文件读取或网络传输操作,从而提高Tomcat对静态文件的处理性能
protocol="org.apache.coyote.http11.Http11AprProtocol"
2
3
4
5
6
7
8
9
10
11
下表展示了不同 Connector 之间的区别:
- | Java Nio Connector NIO | Java Nio2 Connector NIO2 | APR/native Connector APR |
---|---|---|---|
Classname | Http11NioProtocol | Http11Nio2Protocol | Http11AprProtocol |
Tomcat Version | since 6.0.x | since 8.0.x | since 5.5.x |
Support Polling | YES | YES | YES |
Polling Size | maxConnections | maxConnections | maxConnections |
Read Request Headers | Non Blocking | Non Blocking | Non Blocking |
Read Request Body | Blocking | Blocking | Blocking |
Write Response Headers and Body | Blocking | Blocking | Blocking |
Wait for next Request | Non Blocking | Non Blocking | Non Blocking |
SSL Support | Java SSL or OpenSSL | Java SSL or OpenSSL | OpenSSL |
SSL Handshake | Non blocking | Non blocking | Blocking |
Max Connections | maxConnections | maxConnections | maxConnections |
TIPS
表格来自 http://tomcat.apache.org/tomcat-9.0-doc/config/http.html#Connector_Comparison[3]
connectionUploadTimeout:指定上传时的超时。disableUploadTimeout 需设置成 false 才有效
disableUploadTimeout:设置为 true,上传超时使用 connectionTimeout,设置成 false,上传超时使用 connectionUploadTimeout。默认 true
redirectPort:表示安全通信(https)转发端口
executor:指定 executor 名称。如果设置了此属性,则 Connector 将使用该 Executor 执行程序。如果不设置 executor 属性,则 Connector 将使用内部私有的 Executor 来提供线程池。该属性主要用来实现在多个 Connector 及其他组件之间共享线程池。
TIPS
压缩带来的好处是减少带宽,但缺点在于增加了服务器的 CPU 开销。就笔者个人的经验,很少直接用 Tomcat 的 GZIP 功能,更多使用 NGINX 的 GZIP。
# 1.3 maxConnections、maxThreads、acceptCount 之间的关系
minSpareThreads, maxThreads 只跟线程数量有关。acceptCount TCP 最大链接数, maxConnections 相当于线程池阻塞队列的大小+maxThreads
我们把 Tomcat 想象成是一个餐厅,请求就像是去就餐的顾客。这个餐厅非常火爆,当处理不过来的时候,就会排号。
# acceptCount:
可以类比为餐厅的排号处能够容纳排号的最大数量,排号的数量不是无限制的,一旦达到上限,就说已经客满(直接返回 connection refused)
# maxConnections:
可以类比为餐厅的大堂的餐桌数量,也就是可以就餐的桌数。
- 如果当前连接数尚未达到 maxConnection,说明还有空闲的餐桌,直接上桌即可。
- 如果所有餐桌都已经坐满,但是排号人数尚未达到 acceptCount,那么就排个号,等着叫号(此时,尽管还能接受请求,但是不会处理你的请求,除非有桌子空闲了)
- 如果取号的人数已经达到 acceptCount,则取号失败,直接拒绝服务(直接返回 connection refused)
# maxThreads:
可以类比为厨师的个数。厨师一开始只有 10 个(最少 minSpareThreads 个),如果发现忙不过来的时候,就会增加几个厨师,一致增加到 maxThreads 个厨师。如果还是不够,那就只能慢慢等着上菜了。这就像是你去吃饭,有时候上一道菜都吃完了,下一道菜还没有上。只不过,在计算机的世界,厨师的数量也不能无止境地增加下去。因为线程数目只要超过 CPU 核心数,就会存在 CPU 切换的开销,线程数越多,切换开销越大,所以说 maxThreads 设置也不能太大。
参数 | 说明 |
---|---|
maxConnections | 最大连接数,当到达该值后,服务器接收但不会处理更多的请求, 额外的请 求将会阻塞直到连接数低于 maxConnections 。可通过 ulimit -a 查看服务器限制。对于 CPU 要求更⾼(计算密集型)时,建议不要配置过大 ; 对于 CPU 要求不是特别⾼时,建议配置在2000左右(受服务器性能影响)。 当然这个需要服务器硬件的⽀持 |
maxThreads | 最大线程数,需要根据服务器的硬件情况,进行⼀个合理的设置 |
acceptCount | 最大排队等待数,当服务器接收的请求数量到达 maxConnections ,此时 Tomcat 会将后⾯的请求,存放在任务队列中进行排序, acceptCount 指的就是任务队列中排队等待的请求数 。 ⼀台 Tomcat 的最大的请求处理数量, 是 maxConnections+acceptCount |
# 1.4 Executor 常用属性
定义线程池,从而在多个 Connector(主要)及其他组件之间共享。Executor 必须实现 org.apache.catalina.Executor 接口。
常用属性如下:
TIPS
这里只列出了 Connector 常用属性,,要想阅读完整属性,可使用如下方式:
•方式一、访问 http://tomcat.apache.org/tomcat-9.0-doc/config/executor.html[4] ,将 9.0 修改为你的 Tomcat 版本即可,比如想看 Tomcat 8 的文档,可将 9.0 改为 8.0•方式二、下载 Tomcat 并启动,访问
/docs/config/executor.html
路径即可。例如:http://localhost:8080/docs/config/executor.html
className:Executor 的实现类。必须实现 org.apache.catalina.Executor 接口。默认值为 org.apache.catalina.core.StandardThreadExecutor
name:Executor 名称,必填且必须唯一
threadPriority:指定线程的优先级,默认 5(Thread.NORM_PRIORITY)
daemon:是否为守护线程,默认 true
namePrefix:指定 Executor 创建的线程的名称前缀。线程名称格式为 namePrefix+threadNumber
maxThreads:活动线程的最大数量,默认 200
minSpareThreads:使用保持活动状态的最小线程数(空闲和活动),默认 25
maxIdleTime:线程最大空闲时间,单位毫秒,默认 60000(1 分钟)。达到该时间后就会把该线程关闭(当然如果当前活动线程数 < minSpareThreads 不会关闭)
maxQueueSize:拒绝执行之前可以排队等待执行的任务数量,默认 Integer.MAX_VALUE
prestartminSpareThreads:在启动 Executor 时是否就启动 minSpareThreads 个线程,默认 false
threadRenewalDelay:如果配置了 ThreadLocalLeakPreventionListener,它将会通知 Executor 有关上下文停止的信息。一旦上下文停止后,线程池中的线程将会被更新。为了避免同时更新线程,可用此属性设置更新的延迟。默认 1000,单位毫秒,如果设成负数,则线程不会被更新。
# 1.5 其他调优参数
# Host
Host 表示虚拟主机。
- server.xml
<Host name="localhost" autoDeploy="true"></Host>
这里只列出了 Host 的调优属性,,要想阅读完整属性,可使用如下方式:
•方式一、访问 http://tomcat.apache.org/tomcat-9.0-doc/config/host.html[5] ,将 9.0 修改为你的 Tomcat 版本即可,比如想看 Tomcat 8 的文档,可将 9.0 改为 8.0•方式二、下载 Tomcat 并启动,访问
/docs/config/host.html
路径即可。例如:http://localhost:8080/docs/config/host.html
- autoDeploy:是否要让 Tomcat 周期性检查新的或更新了的 Web 应用程序。如果设为 true,则 Tomcat 会定期检查 appBase 和 xmlBase 目录,并自动部署。默认 true。由于 autoDeploy=true 时,会启用一个定时任务,如果没有“自动部署”的需求,可将其设为 false。
# 1.6 Spring Boot/Spring Cloud 项目支持的调优参数
# 开发环境配置
server:
tomcat:
# tomcat的URI编码
uri-encoding: UTF-8
# 等价于Connector.acceptCount,连接数满后的排队数,默认为100
accept-count: 1000
# 等价于Connector.maxConnections 默认 8192
max-connections: 1000
connection-timeout: 60s
threads:
# 等价于Connector.maxThreads tomcat最大线程数,默认为200
max: 1000
# 等价于Connector.minSpareThreads Tomcat启动初始化的线程数,默认值10
min-spare: 10
# TIPS:压缩带来的好处是减少带宽,但缺点在于增加了服务器的CPU开销。就笔者个人的经验,很少直接用Tomcat的GZIP功能,更多使用NGINX的GZIP。
compression:
# 是否开启GZIP,默认关闭
enabled: false
# 执行压缩所需的最小响应大小,默认2KB
min-response-size: 2KB
# 想要GZIP的格式,默认"text/html", "text/xml", "text/plain",
"text/css", "text/javascript", "application/javascript", "application/json",
"application/xml"
mime-types: "text/html", "text/xml"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 1.7 其他调优
# Tomcat Session 调优
# 一、JSP 与 Session
如果使用 JSP 的话,如果业务允许,考虑考虑加上以下内容:
<%@ page session="false" %>
高并发场景下,可能会导致内存溢出。
# 二、为 Session 设置合理的超时
超时时间不宜过长,否则也可能会造成内存上的压力。
对于传统 Tomcat 项目,只需在应用的 web.xml
中添加如下内容:
<!-- 配置Session失效时间,单位分钟 -->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
2
3
4
对于 Spring Boot 项目,通过如下配置设置 Session 即可。
server:
servlet:
session:
timeout: 30m
2
3
4
拓展阅读
其他设置 Session 超时时间的方法详见 https://www.iteye.com/blog/jiangshuiy-1843622[7]
# 2. 虚拟机运行优化(参数调整)
# 1 虚拟机运行优化(参数调整)
Java 虚拟机的运行优化主要是内存分配和垃圾回收策略的优化:
- 内存直接影响服务的运行效率和吞吐量
- 垃圾回收机制会不同程度地导致程序运行中断(垃圾回收策略不同,垃圾回收次数和回收效率都是 不同的)
# 1.1Java 虚拟机内存相关参数
参数 | 参数作⽤ | 优化建议 |
---|---|---|
-server | 启动 Server,以服务端模式运行 | 服务端模式建议开启 |
-Xms | 最⼩堆内存 | 建议与-Xmx 设置相 同 |
-Xmx | 最大堆内存 | 建议设置为可⽤内存 的 80% |
-XX:MetaspaceSize | 元空间初始值 | |
- XX:MaxMetaspaceSize | 元空间最大内存 | 默认⽆限 |
-XX:NewRatio | 年轻代和⽼年代大⼩⽐值,取值为整数,默 认为 2 | 不需要修改 |
-XX:SurvivorRatio | Eden 区与 Survivor 区大⼩的⽐值,取值为整 数,默认为 8 | 不需要修改 |
参数调整示例
JAVA_OPTS="-server -Xms2048m -Xmx2048m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m"
# 2. 垃圾回收(GC)策略
垃圾回收性能指标
- 吞吐量:工作时间(排除 GC 时间)占总时间的百分⽐, 工作时间并不仅是程序运行的时间,还包含内存分配时间。
- 暂停时间:由垃圾回收导致的应⽤程序停⽌响应次数/时间。
垃圾收集器
串行收集器(Serial Collector)
单线程执行所有的垃圾回收工作, 适⽤于单核 CPU 服务器
工作进程-----|(单线程)垃圾回收线程进行垃圾收集|---工作进程继续
并行收集器(Parallel Collector)
工作进程-----|(多线程)垃圾回收线程进行垃圾收集|---工作进程继续
⼜称为吞吐量收集器(关注吞吐量), 以并行的方式执行年轻代的垃圾回收, 该方式可以显著降低垃圾回收的开销(指多条垃圾收集线程并行工作,但此时⽤户线程仍然处于等待状态)。适⽤于多处理器或多线程硬件上运行的数据量较大的应⽤
并发收集器(Concurrent Collector)
以并发的方式执行大部分垃圾回收工作,以缩短垃圾回收的暂停时间。适⽤于那些响应时间优先于吞吐量的应⽤, 因为该收集器虽然最⼩化了暂停时间(指⽤户线程与垃圾收集线程同时执行,但不⼀定是并行的,可能会交替进行), 但是会降低应⽤程序的性能
CMS 收集器(Concurrent Mark Sweep Collector)
并发标记清除收集器, 适⽤于那些更愿意缩短垃圾回收暂停时间并且负担的起与垃圾回收共享处理器资源的应⽤。低延迟
G1 收集器(Garbage-First Garbage Collector)
适⽤于大容量内存的多核服务器, 可以在满⾜垃圾回收暂停时间⽬标的同时, 以最大可能性实现 ⾼吞吐量(JDK1.7 之后)。高并发,高吞吐量
# References
[1]
: https://blog.csdn.net/zzzgd_666/article/details/88740198 [2]
: http://tomcat.apache.org/tomcat-9.0-doc/config/http.html [3]
: http://tomcat.apache.org/tomcat-9.0-doc/config/http.html#Connector_Comparison [4]
: http://tomcat.apache.org/tomcat-9.0-doc/config/executor.html [5]
: http://tomcat.apache.org/tomcat-9.0-doc/config/host.html [6]
: Tomcat 调优之从 Linux 内核源码层面看 Tcp backlog (opens new window)
- 01
- idea 热部署插件 JRebel 安装及破解,不生效问题解决04-10
- 02
- spark中代码的执行位置(Driver or Executer)12-12
- 03
- 大数据技术之 SparkStreaming12-12