Tomcat是我们经常使用的 servlet容器之一,甚至很多线上产品都使用 Tomcat充当服务器。而且优化后的Tomcat性能提升显著,总结了几方面进行分析优化。
一、配置优化
TOMCAT_HOME/conf/server.xml
可以配置端口,虚拟路径等等 Tomcat相关主要配置。
1.Connector 优化
Connector是连接器,负责接收客户的请求,以及向客户端回送响应的消息。所以 Connector的优化是重要部分。默认情况下 Tomcat只支持200线程访问,超过这个数量的连接将被等待甚至超时放弃,所以我们需要提高这方面的处理能力。
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
1)port:代表Tomcat监听端口,也就是网站的访问端口,默认为8080,可以根据需要改成其他。
2)protocol:协议类型,可选类型有四种,分别为BIO(阻塞型IO),NIO,NIO2和APR。
- BIO:BIO(Blocking I/O),顾名思义,即阻塞式I/O操作,表示Tomcat使用的是传统的Java I/O操作(即java.io包及其子包)。Tomcat在默认情况下,是以bio模式运行的。遗憾的是,就一般而言,bio模式是三种运行模式中性能最低的一种。BIO配置采用默认即可。
- NIO:NIO(New I/O),是Java SE 1.4及后续版本提供的一种新的I/O操作方式(即java.nio包及其子包)。Java nio是一个基于缓冲区、并能提供非阻塞I/O操作的java API,因此nio也被看成是non-blocking I/O的缩写。它拥有比传统I/O操作(bio)更好的并发运行性能。要让Tomcat以nio模式来运行也比较简单,我们只需要protocol类型修改为:
//NIO
protocol="org.apache.coyote.http11.Http11NioProtocol"
//NIO2
protocol="org.apache.coyote.http11.Http11Nio2Protocol"
3)maxThreads:由该连接器创建的处理请求线程的最大数目,也就是可以处理的同时请求的最大数目。如果未配置默认值为200。 maxThreads是一个重要的配置属性,maxThreads配置的合理直接影响了Tomcat的相关性能,需要重点关注。maxThreads并不是配置的越大越好,事实上即使配置成999999也是没有用的,因为这个最大值是受操作系统及相关硬件所制约的,并且最大值并不一定是最优值,所以我们追寻的应该是最优值而不是最大值。
QPS(Query Per Second):每秒查询率QPS,(服务器每秒能处理的流量)对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准。我们常常使用QPS值来衡量一个服务器的性能。
一个系统吞吐量(所谓吞吐量这里可以理解为每秒能处理请求的次数)通常由QPS、并发数两个因素决定,每套系统的这两个值都有一个相对极限值,在应用场景访问压力下,只要某一项达到系统最高值,系统的吞吐量就上不去了,如果压力继续增大,系统的吞吐量反而会下降,原因是系统超负荷工作,上下文切换、内存等等其它消耗导致系统性能下降。
- 通过线上系统不断使用和用户的不断增长来进行性能测试,观察QPS,响应时间,这种方式会在爆发式增长时系统崩溃,如双12等。
- 根据公式计算,服务器端最佳线程数量=((线程等待时间+线程cpu时间)/线程cpu时间) * cpu数量,这种方式有时会被误导,因为某些系统处理环节可能会耗时比较长,从而影响公式的结果。
- 单、多用户压力测试,查看CPU的消耗,然后直接乘以百分比,再进行压测,一般这个值的附近应该就是最佳线程数量,这种方式理想场景比较适用,实际情况会比这个复杂的多。
- 根据系统的自身情况调整,如硬件限制,系统限制,程序处理能力限制等。
- 定期修改为不同的
maxThreads
值,看服务器响应结果及用户反应。
QPS和线程数的关系
- 在最佳线程数量之前,QPS和线程是互相递增的关系,线程数量到了最佳线程之后,QPS持平,不在上升,甚至略有下降,同时相应时间持续上升。
- 同一个系统而言,支持的线程数越多(最佳线程数越多而不是配置的线程数越多),QPS越高。
QPS和响应时间的关系
- 对于一般的web系统,响应时间一般有CPU执行时间+IO等待时间组成。
- CPU的执行时间减少,对QPS有实质的提升,IO时间的减少,对QPS提升不明显。如果要想明显提升QPS,优化系统的时候要着重优化CPU消耗大户。
所以想要找出 maxThreads的最优值可并不容易,没有最好只有更好,更好的值只能通过时间来显现,如果你不想考虑那么多,一般情况下设置成1000即可。
测试并不一定某种protocol就一定性能出色,因为Tomcat中的这个测试项目只有一个index.jsp页面,在较少线程数访问情况下BIO反应最快,而当线程数达到1000时NIO2性能最出色,而APR中规中矩,虽然这种测试的局限性很大,但也可以反映出:想要找出适合的配置及最佳性能需要结合实际,不断的测试与改进,最终才能达到一个相对稳定的性能,虽然此时的性能未必是最佳的,但却是能应对绝大多数情况的。
BIO更适合处理简单流程,如程序处理较快可以立即返回结果。简单项目及应用可以采用BIO。
NIO更适合后台需要耗时完成请求的操作,如程序接到了请求后需要比较耗时的处理这已请求,所以无法立即返回结果,这样如果采用BIO就会占用一个连接,而使用NIO后就可以将此连接转让给其他请求,直至程序处理完成返回为止。
APR可以大大提升Tomcat对静态文件的处理性能,同时如果你使用了HTTPS方式传输的话,也可以提升SSL的处理性能。
2.线程池优化
Executor代表了一个线程池,可以在Tomcat组件之间共享。使用线程池的好处在于减少了创建销毁线程的相关消耗,而且可以提高线程的使用效率。要想使用线程池,首先需要在 Service标签中配置 Executor,如下:
<Service name="Catalina">
<Executor name="tomcatThreadPool"
namePrefix="catalina-exec-"
maxThreads="1000"
minSpareThreads="100"
maxIdleTime="60000"
maxQueueSize="Integer.MAX_VALUE"
prestartminSpareThreads="false"
threadPriority="5"
className="org.apache.catalina.core.StandardThreadExecutor"/>
....
name:线程池名称,用于 Connector中指定。
namePrefix:所创建的每个线程的名称前缀,一个单独的线程名称为 namePrefix+threadNumber。
maxThreads:池中最大线程数。
minSpareThreads:活跃线程数,也就是核心池线程数,这些线程不会被销毁,会一直存在。
maxIdleTime:线程空闲时间,超过该时间后,空闲线程会被销毁,默认值为6000(1分钟),单位毫秒。
maxQueueSize:在被执行前最大线程排队数目,默认为Int的最大值,也就是广义的无限。除非特殊情况,这个值不需要更改,否则会有请求不会被处理的情况发生。
prestartminSpareThreads:启动线程池时是否启动 minSpareThreads部分线程。默认值为false,即不启动。
threadPriority:线程池中线程优先级,默认值为5,值从1到10。
className:线程池实现类,未指定情况下,默认实现类为org.apache.catalina.core.StandardThreadExecutor。如果想使用自定义线程池首先需要实现 org.apache.catalina.Executor接口。
线程池配置完成后需要在 Connector中指定:
<Connector executor="tomcatThreadPool"
...
网友评论