tomcat参数:
MaxConnections
MaxThreads
AcceptCount
ConnectionTimeout
最近学习了下tomcat源码,把上面四个参数相关的逻辑整理了下 如下图。(下图是nio的方式,nio2的实现基本相同,没有了Poller,直接在Acceptor里调用jdk AIO 的accept().get()阻塞。对这几个参数的效果无影响)
1.AcceptCount:
Tcp三次握手结束后的就绪队列长度,如果超过此队列长度,则会丢弃或者返回RST.
源码 Nio2Endpoint.bind() 里用到了:
这里的getBacklog就是获取我们设置的AcceptCount值。
2.MaxConnections:
虽然这个参数名字是最大连接数,但是官方注释里也说了,如果超过这个值,依然会接受连接,但是不会处理。所以其实这个参数可以理解为,正在处理,或等待处理的请求数,如果超过这个值,则acceptor则被阻塞,不会从上面的就绪队列取连接来处理。
源码 Nio2Endpoint 的内部类 Acceptor 的run 方法里实现的阻塞:
这里的阻塞和计数是tomcat里面的LimitLatch类实现的,是通过一个内部类继承aqs实现的。
3.MaxThreads
第一张图里worker线程池的最大线程数,也就是实际处理请求的最大线程数。
源码里 AbstractEndpoint.createExecutor 方法负责创建该线程池:
1.这里可以看到该线程池的最大线程数使用的是我们设置的MaxThreads。
2.需要注意这里使用的队列的长度,默认值是Integer.MAX_VALUE,这样相当于无界队列,线程池始终都无法达到最大线程数。
3.但是tomcat自己实现的TaskQueue改写了offer方法,达到了同样效果
总结:
由于worker线程池的队列是无界的,所以当MaxConnections 设置的比较大时,就有可能导致进入队列等待的请求太多,导致每个请求都被处理了,但是处理时间都比较长。
个人感觉这里有两种配法:
1. MaxConnections 可以配置成和 MaxThreads一样大,这样就不会有请求进入到worker线程池的队列里等待,因为本身我们已经有了tcp的就绪队列做缓冲队列。
2.由于tcp的就绪队列受操作系统的影响,不同操作系统可能有不同情况。所以也可以使用worker线程池的队列来做缓冲队列,比如我们核心线程数为1000,队列长度希望是500,就可以把MaxConnections 设置为1500,来达到同样的效果。
下面是做的测试:
tomcat配置如下:
处理逻辑直接sleep10秒,同时发送10条请求,结果10次请求都成功了,但是每条请求的响应时间都很长,说明这些请求都成功的进入了worker的等待队列,最终都被处理。
如果将参数MaxConnections 设置为2时:
同时发送10条请求,结果只有前三次成功处理,后面7次都直接返回502了,说明由于MaxConnections 的阻塞,后面7个请求都由于Tcp的就绪队列满导致直接失败。
源码tomcat版本:8.5.14