目的
Tomcat是我们经常使用的 servlet容器之一,甚至很多线上产品都使用 Tomcat充当服务器。而且优化后的Tomcat性能提升显著,本文从以下几方面进行分析优化。
JVM内存优化
默认情况下Tomcat的相关内存配置较低,这对于一些大型项目显然是不够用的,这些项目运行就已经耗费了大部分内存空间,何况大规模访问的情况。即使是本文中的这个只有一个页面的超小项目,在并发达到一定程度后也会抛出OOM(OutOfMemoryError)的异常报错。
OOM报错:说明Tomcat已经无力支持访问处理,内部GC也已经“无能无力”。所以一般情况下我们需要重新配置Tomcat的相关内存大小。
配置
Linux下修改TOMCAT_HOME/bin/catalina.sh,在其中加入,可以放在CLASSPATH=下面:
1 | JAVA_OPTS="-server -Xms2048m -Xmx2048m -XX:PermSize=512M -XX:MaxPermSize=1024m" |
windows下修改TOMCAT_HOME/bin/catalina.bat,在其中加入,可以放在set CLASSPATH=下面:
1 | set JAVA_OPTS=-server -Xms2048m -Xmx2048m -XX:PermSize=512M -XX:MaxPermSize=1024m |
这些参数在我们学习JVM部分文章时已经都认识过了,不过这里还是简单介绍下:
1 | -server:启用 JDK的 server 版本; |
除了这些参数外您还可以根据具体需要配置其他参数,可以参考JVM参数的配置JDK7和JDK8。
验证
设置成功后我们可以利用JDK自带的工具进行验证,这些工具都在JAVA_HOME/bin目录下:
1)jps:用来显示本地的java进程,以及进程号,进程启动的路径等。
2)jmap:观察运行中的JVM 物理内存的占用情况,包括Heap size,Perm size等。
高并发优化
我们知道TOMCAT_HOME/conf/server.xml可以配置端口,虚拟路径等等 Tomcat相关主要配置。
连接器优化
Connector是连接器,负责接收客户的请求,以及向客户端回送响应的消息。所以 Connector的优化是重要部分。默认情况下 Tomcat只支持200线程访问,超过这个数量的连接将被等待甚至超时放弃,所以我们需要提高这方面的处理能力。
修改这部分配置需要修改TOMCAT_HOME/conf/server.xml,打开server.xml找到Connector 标签项,默认配置如下:
1 | <Connector port="8080" protocol="HTTP/1.1" |
其中port代表服务接口;protocol代表协议类型;connectionTimeout代表连接超时时间,单位为毫秒;redirectPort代表安全通信(https)转发端口,一般配置成443。
可以看到除了这几个基本配置外并无特殊功能,所以我们需要对 Connector 进行扩展。
其中Connector 支持参数属性可以参考Tomcat官方网站非常多,所以本文就只介绍些常用的。
我们将 Connector 配置修改为如下:
1 | <Connector port="8080" |
1 | 参数解释: |
连接器还有很多其他参数,可以参考Tomcat官网,这里只介绍与性能相关的部分。
协议
通过配置 protocol的类型可以使用不同的 Connector处理请求。
1 | //BIO |
以下是几种类型 Connector的参数对比:
并不是说 BIO的性能就一定不如 NIO,这几种类型 Connector之间并没有明显的性能区别,它们之间实现流程和原理不同,所以它们的选择是需要根据应用的类型来决定的。
BIO更适合处理简单流程,如程序处理较快可以立即返回结果。简单项目及应用可以采用BIO。
NIO更适合后台需要耗时完成请求的操作,如程序接到了请求后需要比较耗时的处理这已请求,所以无法立即返回结果,这样如果采用BIO就会占用一个连接,而使用NIO后就可以将此连接转让给其他请求,直至程序处理完成返回为止。
APR可以大大提升Tomcat对静态文件的处理性能,同时如果你使用了HTTPS方式传输的话,也可以提升SSL的处理性能。详见Tomcat优化之APR模式
线程池
Executor代表了一个线程池,可以在Tomcat组件之间共享。使用线程池的好处在于减少了创建销毁线程的相关消耗,而且可以提高线程的使用效率。
要想使用线程池,首先需要在 Service标签中配置 Executor,如下:
1 | <Service name="Catalina"> |
1 | 参数解释: |
线程池配置完成后需要在 Connector中指定:
1 | <Connector executor="tomcatThreadPool" |
监听器
另一个影响Tomcat 性能的因素是内存泄露。Server标签中可以配置多个Listener,其中 JreMemoryLeakPreventionListener是用来预防JRE内存泄漏。此Listener只需在Server标签中配置即可,默认情况下无需配置,已经添加在 Server中。
1 | <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" /> |
性能测试
Tomcat优化部分我们已经完成,接下来就需要比较一下优化前与优化后的性能对比。
Jmeter介绍
Apache JMeter是Apache组织开发的基于Java的压力测试工具。用于对软件做压力测试,它最初被设计用于Web应用测试,但后来扩展到其他测试领域。 它可以用于测试静态和动态资源,例如静态文件、Java小服务程序、CGI 脚本、Java 对象、数据库、FTP 服务器, 等等。JMeter 可以用于对服务器、网络或对象模拟巨大的负载,来自不同压力类别下测试它们的强度和分析整体性能。另外,JMeter能够对应用程序做功能/回归测试,通过创建带有断言的脚本来验证你的程序返回了你期望的结果。为了最大限度的灵活性,JMeter允许使用正则表达式创建断言。
Apache jmeter 可以用于对静态的和动态的资源(文件,Servlet,Perl脚本,java 对象,数据库和查询,FTP服务器等等)的性能进行测试。它可以用于对服务器、网络或对象模拟繁重的负载来测试它们的强度或分析不同压力类型下的整体性能。你可以使用它做性能的图形分析或在大并发负载测试你的服务器/脚本/对象。
Jmeter官网:http://jmeter.apache.org/
Jmeter作用
(1)能够对HTTP和FTP服务器进行压力和性能测试, 也可以对任何数据库进行同样的测试(通过JDBC),Jmeter支持以下服务器协议类型测试:
• Web - HTTP, HTTPS • SOAP / REST • FTP • Database via JDBC • LDAP
• Message-oriented middleware (MOM) via JMS • Mail - SMTP(S), POP3(S) and IMAP(S)
• MongoDB (NoSQL) • Native commands or shell scripts • TCP
(2)完全的可移植性和100% 纯java。
(3)完全 Swing 和轻量组件支持(预编译的JAR使用 javax.swing.*)包。
(4)完全多线程 框架允许通过多个线程并发取样和 通过单独的线程组对不同的功能同时取样。
(5)精心的GUI设计允许快速操作和更精确的计时。
(6)缓存和离线分析/回放测试结果。
Jmeter特性
(1)可链接的取样器允许无限制的测试能力。
(2)各种负载统计表和可链接的计时器可供选择。
(3)数据分析和可视化插件提供了很好的可扩展性以及个性化。
(4)具有提供动态输入到测试的功能(包括JavaScript)。
(5)支持脚本编程的取样器(在1.9.2及以上版本支持BeanShell)。
在设计阶段,JMeter能够充当HTTP PROXY(代理)来记录IE/NETSCAPE的HTTP请求,也可以记录apache等WebServer的log文件来重现HTTP流量。当这些HTTP客户端请求被记录以后,测试运行时可以方便的设置重复次数和并发度(线程数)来产生巨大的流量。JMeter还提供可视化组件以及报表工具把量服务器在不同压力下的性能展现出来。
相比其他HTTP测试工具,JMeter最主要的特点在于扩展性强。JMeter能够自动扫描其lib/ext子目录下.jar文件中的插件,并且将其装载到内存,让用户通过不同的菜单调用。
Jmeter使用
使用Jmeter非常简单,windows下进入bin目录直接双击jmeter.bat文件即可,Linux下类似,需要运行jmeter.sh文件,Jmeter运行后显示以下界面:
Jmeter使用起来比较简单,附件是一个简单的配置,直接导入即可使用。
测试条件
1 | Tomcat版本:8.0.33 |
测试结果
从部分结果来看优化过的Tomcat会比默认性能及并发处理能力上有提高,但至于参数的配置需要结合硬件及操作系统来不断调整,所以并不会有一个万能的参数来使用,需要各位不断的测试不断更改。
以下是一个简单的测试结果,循环100次,线程数分别为10,100,1000:
各位估计已经发现了相同的应用下并不一定某种protocol就一定性能出色,因为Tomcat中的这个测试项目只有一个index.jsp页面,在较少线程数访问情况下BIO反应最快,而当线程数达到1000时NIO2性能最出色,而APR中规中矩,虽然这种测试的局限性很大,但也可以反映出:想要找出适合的配置及最佳性能需要结合实际,不断的测试与改进,最终才能达到一个相对稳定的性能,虽然此时的性能未必是最佳的,但却是能应对绝大多数情况的。
总结:
Tomcat相关优化也只是一个入门介绍,每一种技术之中还是有很多很深奥的知识要去学习,只有不断的去学习才能不断的提高。