目录
1.Tomcat的IO模型
支持的IO模型 | 特点 |
---|---|
BIO | 同步阻塞式IO,每一个请求都会创建一个线程,对性能开销大,不适合高并发场景。 |
NIO | 同步非阻塞式IO,基于多路复用Selector监测连接状态通知线程处理,达到非阻塞的目的,比传统的BIO效率高。Tomcat8.0的默认方式。 |
AIO | 异步IO,基于各种回调处理。 |
APR | Apache Http服务器的支持库,通过JNI技术调用本地库实现非阻塞IO。 |
大部分、默认情况下Tomcat选择的就是NIO模型,大部分场景的网络业务都是扛得住的,到了瓶颈的时候一般也会考虑集群、分布式架构了。
2.NioEndpoint
Tomcat里面NIO的实现是交给Endpoint组件完成的,NioEndpoint是基于JDK的NIO实现的多路复用的IO模型,并且Tomcat的网络模型是主从Reactor多线程模型
。
2.1 LimitLatch
连接控制器,负责控制最大连接数,NIO模式下默认是10000个,当连接数达到最大限制时阻塞线程,直到后续处理完连接后,连接数-1才继续执行。
2.2 Acceptor
连接器由一个单独的线程通过while(true)循环调用#accept( )方法来接收新的连接,一旦有新的连接到达,就会返回一个Channel对象,将Channel对象交给Poller组件处理。
2.3 Poller
Acceptor和Poller是通过SynchronizedQueue
同步队列来进行生产-消费模式进行 通信,Poller的本质就是一个Selector,由一个单独的线程while(true)监测Channel的就绪状态,一旦有Channel可读,就会生成一个SocketProcessor任务对象给Executor线程池处理。
3.Tomcat的线程池拓展
Tomcat并没有使用JDK原生提供的线程池,而是实现了StandardThreadExecutor
,它和原生JDK的线程池ThreadPoolExecutor的区别:
- 自定义了拒绝策略,Tomcat在线程总数达到最大数时,不是立即执行拒绝策略,而是再尝试向任务队列里尝试添加任务,如果添加失败则执行拒绝策略。
- 它的任务队列TaskQueue重写了LinkedBlockingQueue的offer方法,只有当前线程数>核心线程数且小于最大线程数且提交的任务书>当前线程数,会创建新线程。目的是让队列长度无限制时,让线程池有机会创建新的线程。
4.NIO中的对象池技术
Java对象如果遇到高频高并发场景下,它的创建、初始化、GC等都比较耗费资源,为了减少开销,Tomcat使用了对象池技术。对象池技术的目的就是对象的缓存和复用,以空间换时间。SynchronizedStack是一个栈结构的对象池,里面缓存着PollerEvent对象,提高程序整体的性能,避免频繁的new对象和回收。
5.Tomcat调优
Tomcat调优关注的指标有:吞吐量、RT时间、线程池、内存、CPU等。
- threadPriority:设置线程优先级。
- maxThreads:设置线程池中最大线程数,默认200,建议调大(500-800)
- minSpareThreads:设置最小线程数,默认25。
- maxIdleTime:设置线程的最大空闲时间,默认1分钟。
- maxQueueSize:设置线程池中任务队列大小,默认Integer.MAX_VALUE。
- ConnectionTimeout:设置连接的超时时间。
- SpirngBoot中可以实现`TomcatConnectorCustomizer接口`来对Connector进行定制化修改优化,例如可以设置连接参数、线程池大小等。