Tomcat的3个参数acceptCount、maxConnections、
maxThreads
本⽂整理⾃ 深度理解Tomcat的acceptCount、maxConnections、maxThreads ⼀⽂。
参考了 Tomcat组成与⼯作原理
感谢2位博主的分享。
1. Tomcat 由2⼤核⼼组件组成:Connector、Container。
Tomcat 2⼤核⼼组件
图⽚来源
2. Tomcat 处理请求的过程
Tomcat 处理请求的过程
图⽚来源
3. Connector 的 protocol
Connector在处理HTTP请求时,会使⽤不同的protocol。不同的Tomcat版本⽀持的protocol不同,其中最典型的protocol包括BIO、NIO和APR(Tomcat7中⽀持这3种,Tomcat8增加了对NIO2的⽀持,⽽到了Tomcat8.5和Tomcat9.0,则去掉了对BIO的⽀持)。
BIO是Blocking IO,顾名思义是阻塞的IO;NIO是Non-blocking IO,则是⾮阻塞的IO。⽽APR是Apache Portable Runtime,是Apache可移植运⾏库,利⽤本地库可以实现⾼可扩展性、⾼性能;Apr是在Tomcat上运⾏⾼并发应⽤的⾸选模式,但是需要安装apr、apr-utils、
tomcat-native等包。
3.1 BIO & NIO
3.1.1 BIO
⽆论是BIO,还是NIO,Connector处理请求的⼤致流程是⼀样的:
在accept队列中接收连接(当客户端向服务器发送请求时,如果客户端与OS完成三次握⼿建⽴了连接,则OS将该连接放⼊accept队列);在连接中获取请求的数据,⽣成request;调⽤servlet容器处理请求;返回response。为了便于后⾯的说明,⾸先明确⼀下连接与请求的关系:连接是TCP层⾯的(传输层),对应socket;请求是HTTP层⾯的(应⽤层),必须依赖于TCP的连接实现;⼀个TCP连接中可能传输多个HTTP请求。
在BIO实现的Connector中,处理请求的主要实体是JIoEndpoint对象。JIoEndpoint维护了Acceptor和Worker:Acceptor接收socket,然后从Worker线程池中出空闲的线程处理socket,如果worker线程池没有空闲线程,则Acceptor将阻塞。其中Worker是Tomcat⾃带的线程池,如果通过配置了其他线程池,原理与Worker类似。
使⽤ NIO 协议的 Connector.jpg
servlet和tomcat的关系Acceptor接收socket后,不是直接使⽤Worker中的线程处理请求,⽽是先将请求发送给了Poller,⽽Poller是实现NIO的关键。Acceptor向Poller发送请求通过队列实现,使⽤了典型的⽣产者-消费者模式。在Poller中,维护了⼀个Selector对象;当Poller从队列中取出socket后,注册到该Selector中;然后通过遍历Selector,出其中可读的socket,并使⽤Worker中的线程处理相应请求。与BIO类似,Worker也可以被⾃定义的线程池代替。
通过上述过程可以看出,在NIoEndpoint处理请求的过程中,⽆论是Acceptor接收socket,还是线程处理请求,使⽤的仍然是阻塞⽅式;但
在“读取socket并交给Worker中的线程”的这个过程中,使⽤⾮阻塞的NIO实现,这是NIO模式与BIO模式的最主要区别(其他区别对性能影响较⼩,暂时略去不提)。⽽这个区别,在并发量较⼤的情形下可以带来Tomcat效率的显著提升。
4. 三个参数:acceptCount、maxConnections、maxThreads
再回顾⼀下Tomcat处理请求的过程:在accept队列中接收连接(当客户端向服务器发送请求时,如果客户端与OS完成三次握⼿建⽴了连接,则OS将该连接放⼊accept队列);在连接中获取请求的数据,⽣成request;调⽤servlet容器处理请求;返回response。
相对应的,Connector中的⼏个参数功能如下:
acceptCount
accept队列的长度;当accept队列中连接的个数达到acceptCount时,队列满,进来的请求⼀律被拒绝。默认值是100。实际场景中,常见的表象是nginx响应502,Tomcat中没有任何access⽇志,应该调⼤该值。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。