Tomcat优化主要有两个方面:内存优化和并发优化。
① tomcat启动脚本
Tomcat内存优化其实也就是JVM优化,启动时告诉JVM需要多大内存(调优内存是最直接的方式)。配置文件为Windows 下的 catalina.bat,Linux 下的 catalina.sh。
在linux启动Tomcat通常我们会执行bin/startup.sh文件,查看该文件源码会发现,该文件最后会执行catalina.sh脚本文件。
在catalina.sh脚本文件中,会看到如下注释变量释义:
该脚本注释说明了一些CATALINA Server的环境配置,如CATALINA_HOME、CATALINA_BASE、CATALINA_OUT、CATALINA_OPTS以及CATALINA_TMPDIR等。值得注意的是,通常建议自定义环境配置文件放在setenv.sh in CATALINA_BASE/bin
。
② catalina.sh中变量说明
CATALINA_HOME&&CATALINA_BASE
前者是Tomcat安装目录,后者是Tomcat工作目录。CATALINA_BASE该变量是可选的,如果没有配置该变量,则默认使用CATALINA_HOME。那么什么时候下同时配置CATALINA_HOME&&CATALINA_BASE呢?如果我们想要运行Tomcat的 多个实例,但是不想安装多个Tomcat软件副本。那么我们可以配置多个工作目录,每个运行实例独占一个工作目录,但是共享同一个安装目录。
CATALINA_OUT
同样是可选的配置,指向将重定向stdout和stderr的文件的完整路径。默认是$CATALINA_BASE/logs/catalina.out。
CATALINA_OPTS
可选配置。执行“开始”、“运行”或“调试”命令时使用的Java运行时选项。在此处定义的选项(不在JAVA_OPTS中),只能被Tomcat自身使用,不能被stop线程、version命令等运行。使用实例如配置head size,GC logging, JMX ports等。
CATALINA_TMPDIR
可选配置。JVM使用的临时路径(java.io.tmpdir该系统环境变量对应),默认为$CATALINA_BASE/temp。
JAVA_HOME&&JRE_HOME
JAVA_HOME–Java开发环境,JRE_HOME–Java运行环境。jdk1.7后,jdk内嵌了jre。如果JRE_HOME未显示设置,则取JAVA_HOME值。
关于jdk、jre、jvm可以参考博文https://blog.csdn.net/J080624/article/details/78051675。
JAVA_OPTS
可选配置。执行任何命令时使用的Java运行时选项。此处的选项(不在CATALINA_OPTS中)可以被Tomcat自身以及stop进程程、version命令等使用。注释中还有这样一句话-Most options should go into CATALINA_OPTS,也就是说你在JAVA_OPTS配置的参数大多数对CATALINA_OPTS实用,并且被CATALINA_OPTS使用。
CATALINA_PID
可选配置。包含catalina启动java进程的pid文件。这里注释有个彩蛋–when start (fork) is used。
LOGGING_CONFIG
可选配置。覆盖Tomcat默认日志配置文件,默认实例为
LOGGING_CONFIG="-Djava.util.logging.config.file=$CATALINA_BASE/conf/logging.properties"
LOGGING_MANAGER
可选配置。覆盖Tomcat默认的日志管理器,默认实例为
LOGGING_MANAGER="-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager"
③ catalina.sh配置jvm参数实例
在catalina.sh文件中配置jvm的内存空间,如:
JAVA_OPTS="-server -Xms256m -Xmx2048m -XX:PermSize=256m -XX:MaxNewSize=1024m -XX:MaxPermSize=1024M"
-Xms
JVM初始化堆的大小,-Xmx
JVM堆的最大值,实际参数大小根据服务器配置或者项目具体设置。需要注意的是jdk1.8中持久代转换成了元空间,故不再支持PermSize与MaxPermSize参数,替换为了-XX:MetaspaceSize与-XX:MaxMetaspaceSize
。
关于JVM参数参考博文:JVM调优总结(一)之参数配置说明与实例
实例如下:
# 优化参数
① protocol
协议类型,可选类型有4种,BIO(阻塞型IO),NIO,NIO2和APR。
BIO
BIO(Blocking I/O) 阻塞式I/O操作,传统的Java I/O操作(即java.io包及其子包)。Tomcat在默认情况下,是以bio模式运行的,bio模式是三种运行模式中性能最低的一种。BIO配置采用默认即可。
BIO更适合处理简单流程,如程序处理较快可以立即返回结果。简单项目及应用可以采用BIO。
NIO
NIO(New I/O)是Java SE 1.4及后续版本提供的一种新的I/O操作方式(即java.nio包及其子包)。Java nio是一个基于缓冲区、非阻塞I/O操作的Java API它拥有比传统I/O操作(bio)更好的并发运行性能。
NIO更适合后台需要耗时完成请求的操作,如程序接到了请求后需要比较耗时的处理这已请求,所以无法立即返回结果,这样如果采用BIO就会占用一个连接,而使用NIO后就可以将此连接转让给其他请求,直至程序处理完成返回为止。
APR
APR(Apache Portable Runtime/Apache可移植运行时),是Apache HTTP服务器的支持库。你可以简单地理解为:Tomcat将以JNI的形式调用 Apache HTTP服务器的核心动态链接库来处理文件读取或网络传输操作,从而大大地提高 Tomcat对静态文件的处理性能。
APR可以大大提升Tomcat对静态文件的处理性能,同时如果你使用了HTTPS方式传输的话,也可以提升SSL的处理性能。
修改方式
//BIO
protocol="HTTP/1.1"
//NIO
protocol="org.apache.coyote.http11.Http11NioProtocol"
//NIO2
protocol="org.apache.coyote.http11.Http11Nio2Protocol"
//APR
protocol="org.apache.coyote.http11.Http11AprProtocol"
② maxThreads
连接器创建处理请求线程的最大数目,处理同时请求的最大数目,默认值为200。
如果一个执行器与此连接器关联,则忽略此属性,因为该属性将被忽略,所以该连接器将使用执行器而不是一个内部线程池来执行任务。maxThreads是一个重要的配置属性,maxThreads配置的合理直接影响了Tomcat的相关性能。maxThreads并不是配置的越大越好,事实上你即使配置成999999也是没有用的,因为这个最大值是受操作系统及相关硬件所制约的,并且最大值并不一定是最优值,所以我们追寻的应该是最优值而不是最大值。
③ minSpareThreads
线程的最小运行数目,这些始终保持运行(空闲线程)。如果未指定,默认值为10。
④ acceptCount
最大队列长度,一般与maxThreads相同,默认为100。
当所有可能的请求处理线程都在使用时,传入连接请求的最大队列长度。如果未指定,默认值为100。一般是设置的跟 maxThreads一样或一半,此值设置的过大会导致排队的请求超时而未被处理。所以这个值应该是主要根据应用的访问峰值与平均值来权衡配置。
⑤ maxConnections
在任何给定的时间内,服务器将接受和处理的最大连接数。当这个数字已经达到时,服务器将接受但不处理,等待进一步连接(进入队列排队)。NIO与NIO2的默认值为10000,APR默认值为8192。
⑥ connectionTimeout
当请求已经被接受,但未被处理,也就是等待中的超时时间。单位为毫秒,默认值为60000。通常情况下设置为30000。
⑦ maxHttpHeaderSize
请求和响应的HTTP头的最大大小,以字节为单位指定。如果没有指定,这个属性被设置为8192(8 KB)。
⑧ tcpNoDelay
如果为true,服务器socket会设置TCP_NO_DELAY选项,在大多数情况下可以提高性能。缺省情况下设为true。
⑨ compression
是否启用gzip压缩,默认为关闭状态。这个参数的可接受值为“off”(不使用压缩),“on”(压缩文本数据),“force”(在所有的情况下强制压缩)。
⑩ compressionMinSize
如果compression=“on”,则启用此项。被压缩前数据的最小值,也就是超过这个值后才被压缩。如果没有指定,这个属性默认为“2048”(2K),单位为byte。
(11)disableUploadTimeout
这个标志允许servlet Container在一个servlet执行的时候,使用一个不同的,更长的连接超时。最终的结果是给servlet更长的时间以便完成其执行,或者在数据上传的时候更长的超时时间。如果没有指定,设为false。
(12) enableLookups
关闭DNS反向查询。
① 同步阻塞IO(JAVA BIO)
同步并阻塞,服务器实现模式为一个连接一个线程(one connection one thread 想想都觉得恐怖,线程可是非常宝贵的资源),当然可以通过线程池机制改善。
② JAVA NIO 又分为同步非阻塞IO,异步阻塞IO
与BIO最大的区别one request one thread。可以复用同一个线程处理多个connection(多路复用)。
③ 异步非阻塞IO(Java NIO2又叫AIO)
主要与NIO的区别主要是操作系统的底层区别,可以做个比喻:比作快递,NIO就是网购后要自己到官网查下快递是否已经到了(可能是多次),然后自己去取快递。AIO就是快递员送货上门了(不用关注快递进度)。
BIO方式适用于连接数目比较小且固定的架构,这种方式对服务器资源要求比较高,并发局限于应用中,JDK1.4以前的唯一选择,但程序直观简单易理解。
NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂,JDK1.4开始支持。
AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持。
在server.xml中:
实现对Tomcat的IO切换。
APR是从操作系统级别来解决异步的IO问题,大幅度的提高性能. (http://apr.apache.org/)。
APR(Apache Portable Runtime)是一个高可移植库,它是Apache HTTP Server 2.x 的核心,能更好地和其它本地web技术集成,总体上让Java更有效率作为一个高性能web服务器平台而不是简单作为后台容器;
在产品环境中,特别是直接使用Tomcat做WEB服务器的时候,应该使用Tomcat Native来提高其性能,如果不配APR,基本上300个线程狠快就会用满,以后的请求就只好等待.但是配上APR之后,并发的线程数量明显下降,从原来的300可能会马上下降到只有几十,新的请求会毫无阻塞的进来;
在局域网环境测,就算是400个并发,也是一瞬间就处理/传输完毕,但是在真实的Internet环境下,页面处理时间只占0.1%都不到,绝大部分时间都用来页面传输,如果不用APR,一个线程同一时间只能处理一个用户,势必会造成阻塞,所以生产环境下用apr是非常必要的.
安装Apache Tomcat Native Library,直接启动就支持apr(http://tomcat.apache.org/native-doc/)它本身是基于APR的,排除代码问题Tomcat优化到这个层次,可以应对大部分性能需求。
最后,优化的前提条件是良好的代码质量和设计。