对于tomcat的优化,主要是从两个方面入手,第一是,tomcat自身的配置,另一个是tomcat所运行的jvm虚拟机的。
Tomcat的Connector是其接收HTTP请求的关键模块, 可以通过它来指定IO处理模式, 指定处理该Connector接收到的请求的线程数等。需要在 tomcat安装目录的conf目录下server.xml 文件的节点中进行配置。
1.1 Executor线程池配置分析
Executor与Connector同级, 多个Connector可以使用同一个线程池来处理请求.
(1) 默认线程池配置:
maxThreads="150" minSpareThreads="4"/> (2) 自定义线程池示例: maxThreads="200" minSpareThreads="10" maxIdleTime="600000" prestartminSpareThreads="true" maxQueueSize="100" /> (3) 线程池Executor 参数说明: name: 线程池名称. namePrefix: 创建的每个线程的名称前缀, 单独的线程名称为 namePrefix + threadNumber. maxThreads: 线程池中最大并发线程数, 默认值为200, 一般建议设置400~ 800 , 要根据服务器配置和业务需求而定. minSpareThreads: 最小活跃线程数, 也就是核心线程数, 不会被销毁, 会一直存在. prestartminSpareThreads: 是否在启动程序时就生成minSpareThreads个线程, 默认为false, 即不启动. 若不设置为true, 则minSpareThreads的设置就不起作用了. maxIdleTime: 线程最大空闲时间, 超过该时间后, 空闲线程会被销毁, 默认值为6000, 单位为毫秒. maxQueueSize: 最大的等待队列数, 超过则拒绝请求. 默认值为int类型的最大值(Integer.MAX_VALUE), 等同于无限大. 一般不作修改, 避免发生部分请求未能被处理的情况. threadPriority: 线程池中线程的优先级, 默认值为5, 取值范围: 1 ~ 10. className:线程池的实现类, 默认实现类为 org.apache.catalina.core.StandardThreadExecutor.要自定义线程池就需要实现 org.apache.catalina.Executor 接口. 一般的服务器操作都包括两方面:1计算(主要消耗cpu),2等待(io、数据库等)。 第一种极端情况,如果我们的操作是纯粹的计算,那么系统响应时间的主要限制就是cpu的运算能力,此时maxThreads应该尽量设的小,降低同一时间内争抢cpu的线程个数,可以提高计算效率,提高系统的整体处理能力。 第二种极端情况,如果我们的操作纯粹是IO或者数据库,那么响应时间的主要限制就变为等待外部资源,此时maxThreads应该尽量设的大,这样才能提高同时处理请求的个数,从而提高系统整体的处理能力。此情况下因为tomcat同时处理的请求量会比较大,所以需要关注一下tomcat的虚拟机内存设置。 当cpu核心数<线程数时,cpu就需要在多个线程直接来回切换,以保证每个线程都会获得cpu时间,即通常我们说的并发执行。cpu在线程切换时消耗的时间随着线程数量的增加越来越大;如果线程数过大时,cpu会把很多时间用在线程切换上,就没有时间来处理我们的程序了,这样就降低了cpu的效率。所以maxThreads的配置绝对不是越大越好。 现实应用中,maxThreads的配置并没有一个最优值,最好的做法是:在不断测试的基础上,不断调整、优化,才能得到最合理的配置。 1.2 Connector连接池配置分析(引入了线程池) Connector是Tomcat接收请求的入口, 每个Connector都有自己专属的监听端口。 web server允许的最大连接数还受制于操作系统的内核参数设置,通常Windows是2000个左右,Linux是1000个左右。 port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> redirectPort="8443" 是基于SSL的端口, 在需要基于安全通道的场合, 比如当客户端的请求协议是HTTPS时, 将该请求转发到此端口. minSpareThreads="25" 是Tomcat连接器的最小空闲Socket线程数, 默认值为25. 如果当前没有空闲线程, 且没有超过maxThreads, 将一次性创建的空闲线程数量. Tomcat初始化时创建的线程数量也是此值. maxSpareThreads="75" 是最大空闲线程数, 一旦创建的线程超过此值, Tomcat就会关闭不再需要的Socket线程, 默认值为50. 线程数可以大致用 "同时在线用户数、用户每秒操作次数、系统平均操作时间" 来计算. keepAliveTimeout="6000" 是下次请求到来之前, Tomcat保持该连接6000ms. maxKeepAliveRequests="10" # 该连接最大支持的请求数, 超过该请求数的连接也将被关闭(此时就会返回一个Connection: close头给客户端). 1表示禁用长连接, -1表示不限制连接个数, 默认为100, 一般设置在100~200之间. enableLookups="false" # 是否支持反查域名(即DNS解析), 默认为true. 为提高处理能力, 应设置为false. disableUploadTimeout="true" # 上传时是否启用超时机制, 若为true, 则禁用上传超时. connectionTimeout="20000" # 网络连接超时时间, 默认值为20000ms, 设置为0表示永不超时 —— 存在隐患. 通常可设置为30000ms. URIEncoding="UTF-8" # 指定Tomcat容器的URL编码格式. maxHttpHeaderSize="8192" # HTTP请求头信息的最大程度, 超过此长度的部分不予处理. 一般设置为8K即可. maxPostSize="10485760" # 指定POST请求的内容大小, 单位为Byte, 默认大小为2097152(2MB), 10485760为10M. 如果要禁用限制, 可设置为-1. 不要混淆了 异步servlet和非阻塞connector,它们一个是Executor,一个是Connector,两者的工作阶段不同。 Servlet:一个Servelet,就是一个线程一次的执行过程。比如响应doGet(),这个是在一个独立的线程中完成的。 当connector建立连接后,服务器会分配一个线程(可能是从线程池)去服务这个连接,即执行doGet等方法,执行完,回收线程。显然这一步是一个同步的过程,tomcat对应的是Executor。 Connector和Servlet(Executor)可以不共用一个线程,一个维护连接,Executor用独立的线程来服务,tomcat采用的就是这种方式。 tomcat使用线程池,线程最多增加到maxThreads ,如果还有请求进来,那么这些请求就会wait在connector上,如果connector上wait的请求超出了acceptCount ,那么服务器就返回 "connection refused"拒绝连接错误。 1.3 Tomcat Connector三种运行模式(BIO, NIO, APR) Tomcat Connector 是请求接收环节与请求处理环节的连接器,具体点说,就是将接收到的请求传递给Tomcat WEB容器进行处理。Tomcat可以处理的不同协议的请求,例如HTTP协议、AJP协议。其中AJP是Tomcat与其他Web Server(例如Apache Server、IIS等)连接使用的协议。对于HTTP协议,根据处理Socket中IO的方式的不同,又可以分为BIO、NIO、APR方式。 1.3.1 Tomcat Connector默认配置 外部ip访问连接到服务器,会有很多connection(连接),建立、维护、管理这些连接,这就是connector要做的事情。 (一)BIO:(blocking I/O)是指阻塞式I/O操作,Tomcat7或以下,在Linux系统中默认就是以bio模式运行的。一个线程处理一个请求。缺点:并发量高时,线程数较多,浪费资源。 (二)NIO/NIO2:(non-blocking I/O)是非阻塞I/O操作。NIO是一个基于缓冲区并能提供非阻塞I/O操作的Java API,它拥有比传统的BIO更好的并发运行性能。利用Java的异步IO处理,可以通过少量的线程处理大量的请求。Tomcat8在Linux系统中默认使用这种方式。 (三)APR:(Apache Portable Runtime),即Apache可移植运行库,APR的使命是创建和维护一套软件库,以便在不同操作系统(Windows、Linux等)底层实现的基础上提供统一的API,是从操作系统层面解决IO阻塞问题、异步IO问题,大幅度提高服务器的并发处理性能,也是Tomcat生产环境运行的首选方式在apr模式下。Linux如果安装了apr和native,Tomcat直接启动就支持APR。 1.4 AJP协议 AJP(Apache JServ Protocol)是定向包协议。WEB服务器和Servlet容器通过TCP连接来交互;为了节省Socket创建的昂贵代价,WEB服务器会尝试维护一个永久TCP连接到servlet容器,并且在多个请求和响应周期过程会重用连接。 1.4.1 Tomcat的server.xml中的AJP和HTTP连接器区别: HTTP协议:连接器监听8080端口,负责建立HTTP连接。在通过浏览器访问Tomcat服务器的Web应用时,使用的就是这个连接器。 AJP协议:连接器监听8009端口,负责和其他的HTTP服务器建立连接。在把Tomcat与其他HTTP服务器集成时,就需要用到这个连接器。 分析了这么一堆,tomcat8自身的配置优化总结如下: 1 禁用AJP服务 tomcat8默认状态下会启用AJP服务,并且占用8009端口。 我们一般是使用Nginx+tomcat的架构,所以用不着AJP协议,所以把AJP连接器禁用。修改conf下的server.xml文件,将AJP服务禁用掉即可。 2 启用线程池 线程池中的最大线程数,初始化的核心线程数,队列长度这些需要结合项目去设置,通过多次的调试找出更加适合的参数。 3 tomcat8以下的Connector的运行模式为使用nio,tomcat8及以上使用nio2。 通过以上方式可以显著提升应用的吞吐量并降低平均响应时间。 tomcat默认可以使用的内存为128MB,在较大型的应用项目中,这点内存是不够的,需要调大。Tomcat内存优化主要是对tomcat启动参数优化,可以新增或者修改在文件tomcat安装目录下的/bin/catalina.sh 中的JAVA_OPTS参数。 3.1 JAVA_OPTS参数说明: -server 启用jdk 的 server 版; -Xms java虚拟机初始化时的最小内存; -Xmx java虚拟机可使用的最大内存; JAVA_OPTS='-server -Xms【初始化内存大小】 -Xmx【可以使用的最大内存】' 需要把这个两个参数值调大。例如: JAVA_OPTS='-server -Xms256m -Xmx512m' 表示初始化内存为256MB,可以使用的最大内存为512MB 本文参考了诸多资料,并加入了个人的理解和经验,在此做下总结,欢迎交流。