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到底是什么关系呢?
- 将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的执行。一个请求到达服务器后,经过以下关键几步,参见下图:
OS与客户端握手并建立连接,并将建立的连接放入完成队列,不妨叫Acceptor Queque。这个队列的长度就是Connector的acceptCount值。
Tomcat中的acceptor线程,不断从Acceptor Queque中获取连接。
Acceptor Queque队列中没有连接,Acceptor线程继续监视
Acceptor Queque队列中有新连接,Acceptor线程将检查当前的连接数是否超过了maxConnections
如果超过maxConnections,则阻塞。直到连接数小于maxConnections,acceptor线程将请求交由Executor负责执行。
Executor将分配worker线程来处理请求数据的读取,处理(servlet的执行)以及响应。
acceptCount
acceptCount 实际上是Bind Socket时候传递的backlog值,在linux平台下含义是已经建立连接还没有被应用获取的连接队列最大长度。此时,如果请求个数达到了acceptCount,新进的请求将抛出refuse connection.