Tomcat优化参考建议 —— 筑梦之路

linux内核参数调优

1. 打开文件数

ulimit -u 默认值为1024 ,即Linux操作系统对一个进程打开的文件句柄数量的限制。
分为软限制和硬限制

软限制是指Linux在当前系统能够承受的范围内进一步限制用户同时打开的文件数;

硬限制则是根据系统硬件资源状况(主要是系统内存)计算出来的系统最多可同时打开的文件数量。

通常软限制小于或等于硬限制。

nproc 操作系统级别对每个用户创建的进程数的限制。

bash 复制代码
cat >> /etc/security/limits.conf << EOF
*        soft       nofile   655360
*        hard       nofile   655360
*        soft       nproc    655360
*        hard       nproc    655360
EOF

2. TCP连接

bash 复制代码
cat >> /etc/sysctl.conf << EOF
net.ipv4.tcp_tw_reuse = 1 
net.ipv4.tcp_tw_recycle = 1 
net.ipv4.tcp_fin_timeout = 30 
net.ipv4.ip_local_port_range = 10000 65000 
net.ipv4.tcp_max_syn_backlog = 8192 
net.ipv4.tcp_max_tw_buckets = 10000
net.core.somaxconn=8192      # accept队列的长度跟这个参数有关
EOF

sysctl -p --system

JVM参数调优

bash 复制代码
JAVA_OPTS="$JAVA_OPTS -server -Xmn2000m -Xms4000m -Xmx4000m -XX:PermSize=128m -XX:+UseConcMarkSweepGC -XX:MaxPermSize=512m -Djuli-logback.configurationFile=file:$CATALINA_HOME/conf/logback.xml"


tomcat配置文件参数调整

默认值:

<!--
 <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
 maxThreads="150" minSpareThreads="4"/>
 -->
修改为:

<Executor
 name="tomcatThreadPool"
 namePrefix="catalina-exec-"
 maxThreads="500"
 minSpareThreads="30"
 maxIdleTime="60000"
 prestartminSpareThreads = "true"
 maxQueueSize = "100"
/>
参数解释:

maxThreads:最大并发数,默认设置 200,一般建议在 500 ~ 800,根据硬件设施和业务来判断
minSpareThreads:Tomcat 初始化时创建的线程数,默认设置 25
maxIdleTime:如果当前线程大于初始化线程,那空闲线程存活的时间,单位毫秒,默认60000=60秒=1分钟。
prestartminSpareThreads:在 Tomcat 初始化的时候就初始化 minSpareThreads 的参数值,如果不等于 true,minSpareThreads 的值就没啥效果了
maxQueueSize:最大的等待队列数,超过则拒绝请求

tomcat参数调优

主要配置文件conf/server.xml

1. maxThreads

tomcat创建的最大线程数,也就是同时处理的请求最大并发数,默认值是200。
maxThreads如何配置?

一般的服务器操作都包括量方面:

计算(主要消耗cpu)

等待(io、数据库等)

第一种极端情况,如果我们的操作是纯粹的计算,那么系统响应时间的主要限制就是cpu的运算能力,此时maxThreads应该尽量设的小,降低同一时间内争抢cpu的线程个数,可以提高计算效率,提高系统的整体处理能力。

第二种极端情况,如果我们的操作纯粹是IO或者数据库,那么响应时间的主要限制就变为等待外部资源,此时maxThreads应该尽量设的大,这样才能提高同时处理请求的个数,从而提高系统整体的处理能力。此情况下因为tomcat同时处理的请求量会比较大,所以需要关注一下tomcat的虚拟机内存设置和linux的open file限制。

maxThreads我设置的比较大比如3000,当服务的线程数大到一定程度时,一般是2000出头,单次请求的响应时间就会急剧的增加,原因可能是cpu在线程切换时消耗的时间随着线程数量的增加越来越大,cpu把大多数时间都用来在这2000多个线程直接切换上了,当然cpu就没有时间来处理我们的程序了。

不能简单的认为多线程=高效率。其实多线程本身并不能提高cpu效率,线程过多反而会降低cpu效率。

当cpu核心数<线程数时,cpu就需要在多个线程直接来回切换,以保证每个线程都会获得cpu时间,即通常我们说的并发执行。

所以maxThreads的配置绝对不是越大越好。

现实应用中,我们的操作都会包含以上两种类型(计算、等待),所以maxThreads的配置并没有一个最优值,一定要根据具体情况来配置。

最好的做法是:在不断测试的基础上,不断调整、优化,才能得到最合理的配置。

2. acceptCount

当tomcat的线程数达到了最大时,接收排队的最大请求个数。默认值为100。
maxThreads与acceptCount这两个值是如何起作用的呢?

情况1:接受一个请求,此时tomcat起动的线程数没有到达maxThreads,tomcat会起动一个线程来处理此请求。

情况2:接受一个请求,此时tomcat起动的线程数已经到达maxThreads,tomcat会把此请求放入等待队列,等待空闲线程。

情况3:接受一个请求,此时tomcat起动的线程数已经到达maxThreads,等待队列中的请求个数也达到了acceptCount,此时tomcat会直接拒绝此次请求,返回connection refused。

对于第3种情况,等待队列的请求个数这个值可能是由acceptCount参数决定,也有可能由linux内核参数net.core.somaxconn决定。

关联:

tomcat的acceptCount与net.core.somaxconn到底是什么关系呢?

  1. 将tomcat的acceptCount设置为3000 ,net.core.somaxconn设置为8192

那么用ss -lt 指令查看在tomcat起的端口上的send_q值是3000 可见这是acceptCount的值。

2.将tomcat的acceptCount设置为10000,net.core.somaxconn设置为8192

同样用ss -lt指令查看在tomcat起的端口上的send_q值是8192,可见这是somaxconn的值。

所以,acceptCount设置的值要一般小于net.core.somaxconn这个参数,这样acceptCount的值才会起作用。net.core.somaxconn 这个参数默认值是128 ,所以需要改这个参数值。

acceptCount如何配置?

一般是设置的跟maxThreads一样大,这个值应该是主要根据应用的访问峰值与平均值来权衡配置的。

如果设的较小,可以保证接受的请求较快相应,但是超出的请求可能就直接被拒绝;

如果设的较大,可能就会出现大量的请求超时的情况,因为我们系统的处理能力是一定的。

3. maxConnections

Tomcat允许的同时存在的最大连接数。
服务器在任何给定时间将接受并处理的最大连接数。当达到此数量时,服务器将接受但不处理额外的一个连接。这个额外的连接会被阻塞,直到正在处理的连接数低于maxConnections,此时服务器将开始再次接受并处理新的连接。请注意,一旦达到限制,操作系统仍然可能根据acceptCount设置接受连接。默认值因连接器类型而异。对于NIO和NIO2,默认值为10000。对于APR/native,默认值为8192。请注意,在Windows上的APR/native配置中,所设置的值将会减少到小于或等于maxConnections的最大1024的倍数值。这是出于性能方面的考虑。如果设置为-1的值,则禁用maxConnections特性,并且不计数连接。

注意:acceptCount、maxConnections是tcp层相关的参数。

4.connectionTimeOut

connectionTimeOut=10000是说建立一个socket连接后,如果一直没有收到客户端的FIN,也没有数据过来,那么此连接也必须等到10s后,才能被超时释放,我理解是tomcat就直接释放这个连接。以毫秒为单位,server.xml默认设置是20秒。
此连接器在接收到连接后,等待请求 URI 行呈现的毫秒数。使用值 -1 表示无(即无限)超时。默认值为 60000(即 60 秒),但请注意,随 Tomcat 一起提供的标准 server.xml 文件将此值设置为 20000(即 20 秒)。除非将 disableUploadTimeout 设置为 false,否则在读取请求正文(如果有)时也将使用此超时。

bash 复制代码
修改方法:
  vi server.xml 打开server.xml文件
将 
<!--
 <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
 maxThreads="150" minSpareThreads="4"/>
 -->
修改为:
  <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
        maxThreads="1500" minSpareThreads="50" prestartminSpareThreads="true"/>

将

<Connector 
 port="8080" 
 protocol="HTTP/1.1" 
 connectionTimeout="20000" 
 redirectPort="8443" 
 />
修改为

 <Connector executor ="tomcatThreadPool" port="8009" protocol="org.apache.coyote.http11.Http11Nio2Protocol"  connectionTimeout="20000" maxConnections="10000"  redirectPort="8443" acceptCount="1500"/>

扩展延伸

SYN队列称为半连接队列,由内核参数 net.ipv4.tcp_max_syn_backlog 设置。

Accept队列称为完全连接队列,三次握手已经完成,但还未被应用层接收(accept),但也处于ESTABLISHED状态。队列长度由listen的backlog参数和内核的 net.core.somaxconn 参数共同决定。由listen()函数的第二个参数 backlog 指定,内核硬限制由 net.core.somaxconn 限制,即队列长度实际的值由min(backlog,somaxconn) 来决定。

客户端使用connect向服务器发送TCP连接,三次握手就发生了。当1.1步骤 客户端首先发送SYN到达服务端后,内核会把连接信息放到SYN队列中,同时回一个SYN+ACK包给客户端。一段时间后,客户端再次发来ACK包后,内核会把连接从SYN队列中取出,再把这个连接放到ACCEPT队列中。应用服务器调用accept时,其实就是直接从ACCEPT队列中取出已经建立成功的连接套接字。

TCP握手建立连接的流程和队列

tomcat原理

Tomcat大致分为两个部分,Connector组件及Container组件。Connector组件负责控制入口连接,并关联着一个Executor。Container负责Servlet容器的实现,Executor负责具体的业务逻辑,如Servlet的执行。一个请求到达服务器后,经过以下关键几步,参见下图:

  1. OS与客户端握手并建立连接,并将建立的连接放入完成队列,不妨叫Acceptor Queque。这个队列的长度就是Connector的acceptCount值。

  2. Tomcat中的acceptor线程,不断从Acceptor Queque中获取连接。

  3. Acceptor Queque队列中没有连接,Acceptor线程继续监视

  4. Acceptor Queque队列中有新连接,Acceptor线程将检查当前的连接数是否超过了maxConnections

  5. 如果超过maxConnections,则阻塞。直到连接数小于maxConnections,acceptor线程将请求交由Executor负责执行。

  6. Executor将分配worker线程来处理请求数据的读取,处理(servlet的执行)以及响应。

    acceptCount

    acceptCount 实际上是Bind Socket时候传递的backlog值,在linux平台下含义是已经建立连接还没有被应用获取的连接队列最大长度。此时,如果请求个数达到了acceptCount,新进的请求将抛出refuse connection.

相关推荐
微学AI34 分钟前
GPU算力平台|在GPU算力平台部署LLama3大模型的详细教程
服务器·人工智能·gpu算力
Hi2024021739 分钟前
RK3588上CPU和GPU算力以及opencv resize的性能对比测试
linux·opencv·arm·gpu·opencl·算力测试·mali-gpu
无名3871 小时前
FreeSWITCH rtp session 的初始化
java·服务器·前端
众拾达人2 小时前
基于 SSH 的任务调度系统
运维·ssh
凯子坚持 c2 小时前
深度解析如何使用Linux中的git操作
linux·运维·git
早睡早起早日毕业2 小时前
vscode支持ssh远程开发
linux·服务器·vscode·ubuntu·ssh
云计算DevOps-韩老师2 小时前
【网络云SRE运维开发】2025第2周-每日【2025/01/10】小测-【第10章 ACL理论和实操考试】解析
服务器·网络·运维开发
相忘于江湖吧2 小时前
浅尝Appium自动化框架
运维·appium·自动化
只做开心事2 小时前
Linux之线程池与单例模式
linux·单例模式
黑客K-ing2 小时前
网工考试——数据链路层、网络层、传输层
服务器·网络·php