tomcat说明
tomcat参数说明:
tomcat核心参数: max-threads,accept-count,max-connections,connection-timeout
-
max-threads:
tomcat起动的最大线程数,即同时处理的任务个数,默认值为200 -
accept-count:
当accept队列中连接的个数达到acceptCount时,队列满,进来的请求一律被拒绝。默认值是100 -
max-connections
tomcat在任意时刻接收和处理的最大连接数。当Tomcat接收的连接数达到maxConnections时,Acceptor线程不会读取accept队列中的连接;这时accept队列中的线程会一直阻塞着,直到Tomcat接收的连接数小于maxConnections。如果设置为-1,则连接数不受限制。默认值与连接器使用的协议有关:NIO的默认值是10000(万级别),APR/native的默认值是8192,而BIO的默认值为maxThreads200(如果配置了Executor,则默认值是Executor的maxThreads)。
在windows下,APR/native的maxConnections值会自动调整为设置值以下最大的1024的整数倍;如设置为2000,则最大值实际是1024
-
connection-timeout
配置为10000,这个配置导致建立一个socket连接后,如果一直没有收到客户端的FIN,也没有数据过来,那么此连接也必须等到10s后,才能被超时释放。从最后一次接收到数据开始计算,如果在此后10s内没有请求过来的话,tomcat会自动断开连接
tomcat参数之间的关系:
有新请求过来以后,会被存放到tomcat底层用于保存连接的数据结构中,当管理的连接数超过maxConnections值的时候,新来的请求会被存放到accept-count大小的请求队列中。当accept-count请求队列满了以后,新进来的请求将会直接拒绝
测试说明
测试目的:
测试目的了解tomcat中max-threads,accept-count,max-connections,connection-timeout参数之间的关系,做深度测试。
客户端每次请求tomcat请求时,让其挂起2秒钟
服务端测试代码:
@RequestMapping(value = "/test/tomcat/hang", method = RequestMethod.GET)
@ResponseBody
public void testTomcatHang() {
try {
Thread.sleep(1000L * 2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(DateUtil.getTime("yyyy-MM-HH mm:ss") + ":" + Thread.currentThread().getName());
}
测试
测试案例1:
- 服务端参数设置:
tomcat:
uri-encoding: UTF-8
max-threads: 1
accept-count: 1
max-connections: 1
connection-timeout: 1000
- 客户端参数设置:
每个线程请求数: 100
开启线程数: 1
开启连接数: 1
选择测试类型: 2
url地址: localhost:8089
-
服务端测试结果:
测试结果符合预期,由于服务端每次接收请求,让其挂起2s。那么每个请求处理间隔的时间就是2s -
客户端测试结果:
客户端的测试结果是0.49/s,理论值是0.5/s。涉及到建立连接过程等,0.49/s符合预期
-
原理说明:
我们设置的服务端最大的处理线程数为1,最大的连接数为1,此时客户端也只开启了一个连接。在这种情况下,服务端的出了和客户端的处理是一对一的。一个线程处理一个连接请求 -
tomcat参数状态:
# 当前处理的线程数
max-threads: 1
# accept-count中等待连接数
accept-count: 0
# max-connections中管理连接数
max-connections: 1
测试案例2:
tomcat:
uri-encoding: UTF-8
max-threads: 1
accept-count: 1
max-connections: 1
connection-timeout: 1000
- 客户端参数设置:
每个线程请求数: 100
开启线程数: 1
开启连接数: 2
选择测试类型: 2
url地址: localhost:8089
ConnectTimeout : 500ms
- 服务端测试结果:
服务端测试结果,请求有间隔2秒,也有间隔3秒 - 客户端测试结果:
- 原理说明:
当一个线程共享两个连接的时候,意思是在这两个连接之间随机切换。有时候可能是连接A,有时候可能是连接B。但是整体是1/2概率的。
当线程第一次创建连接A的时候,连接A会被放入到connections队列里面,且完成当前请求。当第二次如果随机获得到的连接还是A的情况下,那么直接使用A连接即可,因为服务端设置的超时时间是1s。所以看到处理的间隔时间有2s的。当线程第二次获取到的连接是B,此时的A连接在connections中并没有过期,需要等待1s的时间,所以此时的连接B被放入到accept队列中。当connections中连接A达到过期时间1s的时候,会从connections中移除A连接,同时将accept中的B连接加入到connections中。所以输出的日志中会存在3秒的间隔时间,其中多出来的一秒时间就是连接A的过期时间。 - -tomcat参数状态:
# 当前处理的线程数
max-threads: 1
# accept-count中等待连接数
accept-count: 1
# max-connections中管理连接数
max-connections: 1
测试案例3:
测试案例3,服务端参数不变,客户端参数中,将连接数设置为1。访问线程数设置为2
- 服务端参数设置:
tomcat:
uri-encoding: UTF-8
max-threads: 1
accept-count: 1
max-connections: 1
connection-timeout: 1000
- 客户端参数设置:
每个线程请求数: 100
开启线程数: 2
开启连接数: 1
选择测试类型: 2
url: localhost:8089
ConnectTimeout : 500ms
-
服务端测试结果:
服务的请求处理时间间隔2秒,符合预期 -
客户端测试结果:
通过检测,同时开启2个线程,共享一个连接的时候。一个连接只能被一个线程使用
-
原理说明:
http客户端连接是线程安全的。同一个连接只能被一个线程使用 -
tomcat参数状态:
# 当前处理的线程数
max-threads: 1
# accept-count中等待连接数
accept-count: 0
# max-connections中管理连接数
max-connections: 1
测试案例4:
测试案例4,服务端参数最大连接数设置为2,客户端参数中,将连接数设置为2,线程数设置为2
- 服务端参数设置:
tomcat:
uri-encoding: UTF-8
max-threads: 1
accept-count: 1
max-connections: 2
connection-timeout: 1000
- 客户端参数设置:
每个线程请求数: 100
开启线程数: 2
开启连接数: 2
选择测试类型: 2
url: localhost:8089
ConnectTimeout : 500ms
- 服务端测试结果:
请求结果每隔2s请求一次 - 客户端测试结果:
线程1和线程2的请求交替出现 - 原理说明:
服务端开启connections为2,同时保持两个连接的请求。当客户端线程1,线程2请求发送连接的时候,该连接都被存储到connections中。但是此时服务端的处理线程数设置为1,所以一次只能处理一个请求。
客户端中的线程1,线程2的请求结果交替出现。因为在connections中,会把有请求状态的连接放到消费队列中进行消费。队列的属性是先进先出。所以客户端的测试结果是交替出现的
- tomcat参数状态:
# 当前处理的线程数
max-threads: 1
# accept-count中等待连接数
accept-count: 0
# max-connections中管理连接数
max-connections: 2
测试案例5:
测试案例5,服务端最大连接数为2,最大线程数设置为2,客户端参数中,将连接数设置为2,请求线程数设置为2
- 服务端参数设置:
tomcat:
uri-encoding: UTF-8
max-threads: 2
accept-count: 1
max-connections: 2
connection-timeout: 1000
- 客户端参数设置:
每个线程请求数: 100
开启线程数: 2
开启连接数: 2
选择测试类型: 2
url: localhost:8089
ConnectTimeout : 500ms
- 服务端测试结果:
查看JVM中的线程情况,发现服务端开启两个处理http-nio-8089-exec的处理线程。同时服务端的输出结果中我们分发现,同一时刻输出两个请求结果。符合预期值 - 客户端测试结果:
客户端开开启两个线程进行请求,这样QPS达到0.87/s,符合预期 - 原理说明:
服务端的最大处理线程数设置为2时,可以同时处理2个客户端连接请求。这样服务端的请求结果同一时刻会出现两次,同时客户端的qps会扩大两倍左右 - tomcat参数状态:
# 当前处理的线程数
max-threads: 2
# accept-count中等待连接数
accept-count: 0
# max-connections中管理连接数
max-connections: 2
总结
- httpclient的连接是线程安全的,同一时刻只能有一个线程可以使用该连接
- 客户端请求连接的时候,首先会被放入到connections中,当connections满了以后,会被存放到accept-count队列中
- 服务端的线程一次只能处理一个请求。当需要处理多个请求的时候,需要开启多个线程
- 当存放在connections队列中的连接,最后一次请求开始计时,当超过其设置的connection-timeout时,会从连接队列中移除。
- connections中默认同时可以管理多个连接,采用的是NIO模式。假设1w个连接,当然这1w个链接也不是都会有读写请求事件发生。当有连接有读写请求事件发生的时候,会把该连接的事件放到Tomcat的TaskQueue中,处理线程会从TaskQueue调用take()方法获取