Tomcat最大线程数、最大连接数、超时时间及高效配置
一、前言
Tomcat 作为 Java Web 程序比较常用的 Servlet 容器实现,在 Web 开发中有比较重要的地位。
二、Tomcat使用的IO模式
Tomcat 有三种 IO 模式,BIO、NIO、APR。在 Tomcat7 及以下 Linux 中默认启用的是 BIO 模式,Tomcat8 及以上使用的是 NIO 模式,利用 Java 的异步 IO 处理,可以通过少量的线程处理大量的连接请求。除这两种方式外,还有一种 APR(Apache Portable Runtime) 模式,从操作系统层面解决 IO 阻塞问题。Tomcat7 或Tomcat8 在 Win7 或以上的系统中启动默认使用这种方式。要注意的是,在 SpringBoot 内嵌的 Tomcat 不自动开启 APR 模式,需要手动进行配置。可以通过启动日志看到 SpringBoot 中启用的 IO 模式:
2021-01-26 17:22:53.076 INFO 8604 --- [nio-9999-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2021-01-26 17:22:53.076 INFO 8604 --- [nio-9999-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2021-01-26 17:22:53.087 INFO 8604 --- [nio-9999-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 10 ms
关于 BIO、NIO、APR 的详解不做过多介绍。
三、Tomcat主要的配置参数
3.1 maxConnections 最大连接数
这个参数是指在同一时间,Tomcat 能够接受的最大连接数。对于 Java 的阻塞式 BIO,默认值是 maxthreads 的值;可以通过配置 Executor 执行器来修改这个值。对于 Java 新的 NIO 模式,maxConnections 默认值是 10000。对于 windows 上 APR/native IO模式,maxConnections 默认值为 8192,这是出于性能原因,如果配置的值不是 1024 的倍数,maxConnections 的实际值将减少到 1024 的最大倍数。如果设置为 -1,则禁用 maxconnections 功能,表示不限制tomcat容器的连接数。
简单来说就是 Tomcat 总共允许建立多少连接。
3.2 maxThreads 最大线程数
每一次 Http 请求到达 Web 服务,Tomcat 都会创建一个线程来处理该请求,最大线程数决定了 Web 服务同时可以处理多少请求。maxThreads 默认值为 200,建议增加,但是增加线程是有成本的,更多的线程代表会有更多的上下文切换,也意味着 JVM 会分配更多的内存。
3.3 acceptCount 排队连接数
当 Tomcat 的最大连接数 maxConnections 被占满之后,后续的请求就会进行排队,排队的最大数量就是 acceptCount,举个例子,当前 maxConnections 为 10,acceptCount 为 5,并且 maxConnections 已经使用了 10,那么后续的请求就会排队,每来一个请求,acceptCount 就会 +1 ,当 acceptCount 增加到 5 ,在后续的请求就会被直接放弃。
3.4 connection-timeout 连接建立时间
HTTP 协议运行在 TCP 之上,所以每次请求到来,客户端和服务端会建立一次 TCP 连接,建立连接需要三次握手,所以就需要一定的时间,connection-timeout 限制了连接建立的时间,当建立连接时间超过这个值,连接就会建立失败。默认为 20000ms。
四、高效配置
常用配置:
server:
tomcat:
accept-count: 100
threads:
# 1核2g内存为200,4核8g内存为800
max: 800
# 最小空闲线程数量,保证线程池中一直有最少100个线程,防止流量激增
min-spare: 100
# 连接超时时间
connection-timeout: 5000
# 最大连接数,可以适应 APR 模式
max-connections: 8192
五、通俗解释
我们可以把 Tomcat 比作餐厅,餐厅有排队取号区域,餐桌,厨房,厨师。
maxConnections 可以类比为餐桌数量,acceptCount 可以类比为排队取号队列长度,maxThreads 可以类比为厨房里厨师的数量。
当客人来的时候,如果餐桌数量没坐满,客人可以直接上餐桌点餐,点餐之后,厨师就会做这一桌的食物,一个厨师同时只能为一桌服务。
当客人来的时候,如果餐桌坐满了,就需要去排队取号区排队取号,如果取号区人也排满了,餐厅就会赶你走。
由于厨师数量可能少于餐桌的数量,所以会出现多个厨师负责多个餐桌的情况,也就是线程数量不够,连接等待处理的情况。
六、简单的测试
SpringBoot 配置:
server:
port: 9999
tomcat:
accept-count: 1
threads:
max: 10
min-spare: 10
connection-timeout: 100
max-connections: 1
接口定义(模拟处理需要 5 秒):
@GetMapping("/tomcat-meter")
public R<?> tomcatMeter() throws InterruptedException {
TimeUnit.SECONDS.sleep(5);
return Resp.new200("this is tomcat meter");
}
使用 Jmeter 同时使用 50 个线程访问测试:
查看测试报告:
测试结果:只有两个请求请求成功,因为最大连接数为1 ,排队数量为 1,所以最多只能处理两个请求,其余的 48 个请求直接被丢弃。