- by zvane
现在各种MVC框架很多,各框架的优缺点网络上也有很多的参考文章,但介绍各框架性能方面差别的文章却不多,本人在项目开发中,感觉到采用了struts2框架的项目访问速度,明显不如原来采用了struts1框架的项目快,带着这些疑惑,我对各类MVC框架的做了一个简单的性能分析比较,其结果应该说是基本符合预期的,可供大家参考。
测试环境:CPU:酷睿2 T5750,内存:DDR2-667 2G,Web容器:Tomcat6.0,最大线程数设置为1000,操作系统:WinXP-sp3
测试步骤:搭建6个Web工程,如下:
1.纯JSP:不包含任何MVC框架,只有一个测试用的JSP页面。
2.struts1:包含一个Action,不做任何逻辑处理,直接转发到一个JSP页面
3.struts2 JSP:不包含Action,只包含测试JSP页面,直接访问该页面。
4.struts2 单例Action:采用Spring来管理Struts2的Action实例,并配置成单例模式。
5.struts2 多例Action:采用Spring来管理Struts2的Action实例,并配置成单例模式。
6.SpringMVC3:采用Spring来管理Controller实例,包含一个Controller,不做逻辑处理,收到请求后,直接返回到一个JSP页面。
测试结果:
测试工程 |
请求数 |
并发数 |
总时间(s) |
总时间(s) |
总时间(s) |
平均值(s) |
Requests Per Second(每秒处理请求数) |
JSP |
2000 |
200 |
5.55 |
3.59 |
4.11 |
4.42 |
452.83 |
struts1 |
2000 |
200 |
6.77 |
3.83 |
7.00 |
5.86 |
341.03 |
struts2 JSP |
2000 |
200 |
25.20 |
26.30 |
24.11 |
25.20 |
79.35 |
struts2 单例Action |
2000 |
200 |
28.36 |
27.59 |
27.69 |
27.88 |
71.74 |
struts2 多例Action |
2000 |
200 |
31.31 |
31.97 |
39.56 |
34.28 |
58.34 |
SpringMVC3 |
2000 |
200 |
7.16 |
7.50 |
4.27 |
6.31 |
317.09 |
说明:以上测试虽不是非常的精确,但基本能说明一定的问题。每个JSP页面和Action都不包含任何的业务逻辑代码,只是请求转发。每轮测试取三次总时间的平均值。所有工程的测试均全部完成并正常处理请求,没有请求拒绝情况发生。
结论:
1.纯JSP的性能应该最高,这不难理解,JSP被编译成Servlet后,没有任何多余的功能,收到请求后直接处理。(这也验证一句经典的话:越原始效率就越高。)
2.struts1的性能是仅次于纯JSP的,由于struts1采用单例Action模式,且本身的封装相比struts2应该说简单很多,虽然开发效率不如struts2,但已经过多年的实践考验,性能稳定高效。
3.相比来说struts2的性能就比较差了,这不难理解,struts2之所以开发方便,是由于采用值栈、OGNL表达式、拦截器等技术对请求参数的映射和返回结果进行了处理,另外还采用大量的标签库等,这些都无疑增加了处理的时间。因此降低了效率。在我们实际的项目中,我测试本地工程访问每秒处理请求数只能达到35左右,应该说还有不少可优化的空间。
4.很多人认为struts2性能差是因为它的多例Action模式导致的,但我们采用spring管理struts2的Action,并设置按单例方式生成Action实例后,发现其性能有所提高,但并不是很明显。由此可见,多例Action模式并不是struts2性能瓶颈所在。另外,我们在struts2中采用JSP方式访问,发现其性能依旧和没有采用任何MVC框架的纯JSP之间存在好几倍的差距,这又从另一个侧面证实了我们刚才得出结论,struts2性能的瓶颈不在于它的多例Action模式。
5.SpringMVC3的性能略逊于struts1,但基本是同级别的,这让人眼前一亮,springMVC有着不比struts2差的开发效率和解耦度,但性能却是struts2的好几倍,这让我们灰常振奋,SpringMVC无疑又是项目开发的一个好的选择。
Struts2、SpringMVC、Servlet(Jsp)性能对比 测试 。
Servlet的性能应该是最好的,可以做为参考基准,其它测试都要向它看齐,参照它。
做为一个程序员,对于各个框架的性能要有一个基本的认知,便于选型时做出正确的决策。
在测试中发现了什么也不要大喊大叫,因为这些都是Java程序员的基础知识。 人人都要了解。
---------------------------------------------------------------------------------------
建议先阅读《你想建设一个能承受500万PV/每天的网站吗? 》一文,了解一些测试的基本概念。在测试开始前就有一个性能好与坏的标准。再用这个标准来检验你程序。
---------------------------------------------------------------------------------------
测试环境说明:
服务器: 4G内存,至强3.0 (4核超线程)CPU,windows 2003
测试机:笔记本 2G内存,p8600 双核CPU,windows XP
网络:100Mb局域网
测试软件:
Jmeter 2.3.4 分配了512M内存
tomcat 6 默认内存大小
---------------------------------------------------------------------------------------
测试配置如下图: 其实jmeter还是很弱的,我打开"集合点(synchronizing Timer)","察看结果树","用表格查看结果"中的任何一个都会导致测试结果中的性能下降和小部分请求的响应出错(可能是线程数太多了),所以禁用了。只启用了cookie管理器。
---------------------------------------------------------------------------------------
Tomcat6.0 配置文件的说明 ,做测试之前是要整清楚的。
默认的Server.xml中如下
Xml代码
- <Connector port="8080" maxHttpHeaderSize="8192"
- maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
- enableLookups="false" redirectPort="8443" acceptCount="100"
- connectionTimeout="20000" disableUploadTimeout="true" />
enableLookups
是否允许DNS查询,当web应用程序要通过域名服务器查找机器名转换为IP地址时。会使用DNS查询,需要占用网络,延长较长
maxThreads
Tomcat可创建的最大的线程数,每一个请求须要一个线程来处理,原来的150太小了,我们测试时并发会超过他的。
acceptCount
指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,就是被排队的请求数,超过这个数的请求将拒绝连接。
connnectionTimeout
网络连接超时,单位:毫秒。设置为0表示永不超时,这样设置有隐患的。通常可设置为20000毫秒。
minSpareThreads
Tomcat初始化时创建的线程数
maxSpareThreads
一旦创建的线程中空闲线程超过这个值,Tomcat就会关闭不再需要的socket线程。
注意:maxThreads 设置为500 ,也就是Tomcat最多同时使用500个线程处理500个并发(服务器CPU不错,500没问题),不要发生 排队等待的情况以免影响测试成绩, 为下面的压力测试做好准备。
---------------------------------测试开始了-------------------------------------------
测试时服务器CPU使用率 10%
测试时测试机CPU使用率 100%(测试机不行啊,主要是 Jmeter的性能一般,又吃内存,测试机p8600 双核CPU还是很强的 )
每次测试CPU都这样,就统一写这里了。
测试1:JSP页面--2213个请求/秒
100并发,循环100次,共10000个请求,请求一个大小3.34KB的jsp页面。
测试2:JSP页面--1889个请求/秒
100并发,循环100次,共10000个请求,请求一个servlet总控制器,验证权限后(很简单),new一个Action,再转发到一个大小3.34KB的jsp页面。
测试3:HTML页面--2607个请求/秒
100并发,循环100次,共10000个请求,请求一个3.2KB的html页面。
测试4: HTML页面-- 833个请求/秒
100并发,循环100次,共10000个请求,请求一个13.4KB的html页面。与上面比是只是文件大了一些,把网卡跑满了 ,网卡成为了性能瓶颈,RPS降了不少!!
测试5: Spring MVC 2012个请求/秒
100并发,循环100次,共10000个请求,请求一个spring3 MVC的action,再转发到一个0.8K的JSP,其内容是简单的html
测试6: Spring MVC 1800-1924个请求/秒
100并发,循环100次,共10000个请求,请求一个spring3 MVC的action,两个参数类型转换为int、Date,再new 一个List,再转发到一个1.3K的JSP,用JSTL标签显示List中的内容。
JSTL标签内容是如下,看来JSTL标签性能还是不错的。
Java代码
- <c:if test="${empty list}">
- <tr>
- <td align="center">无记录!</td>
- </tr>
- </c:if>
- <c:if test="${not empty list}">
- <tr>
- <th>从 1 开始的迭代计数</th>
- <th>从 0 开始的迭代计数</th>
- <th>产品名称</th>
- </tr>
- <c:forEach items="${list}" var="item" varStatus="s">
- <tr bgcolor=${s.index%2==0?"#E2E2E2":""}>
- <td align="center">${s.count} </td>
- <td align="center">${s.index} </td>
- <td align="center">${item} </td>
- </tr>
- </c:forEach>
- </c:if>
测试7: 访问一张图片(srping方式一) 1997个请求/秒
100并发,循环100次,共10000个请求. 因为我使用了spring3 MVC,拦截/,所以图片不能访问,所以添加了:
Xml代码
- <servlet-mapping>
- <servlet-name>default</servlet-name>
- <url-pattern>*.jpg</url-pattern>
- </servlet-mapping>
走默认的servlet,来访问2.5K的图片
测试8: 访问一张图片 (srping方式二) 1967个请求/秒
100并发,循环100次,共10000个请求,因为我使用了spring3 MVC,拦截/,所以图片不能访问,所以添加了:
<mvc:resources mapping="/images/**" location="/images/" cache-period="31556926"/>
来访问2.5K的图片,会走spring的可匹配的一个拦截器。
测试9:Struts2 使用官方提供的示例程序 (使用了Struts2标签 ) 几十个请求/秒
100并发,循环1次,没有循环100次,因为strtus2在这次测试中响应太慢了,我等不起了,所以单个url的测试样本从10000降到了100.一共11个url,共1100个样本。
"spring" 使用的就是前面“测试5”的URL,放在这里是为了与strtus2对比的。
"html" 使用的就是前面“测试3”的URL,放在这里是为了与strtus2对比的。
"struts2-1" 使用的是官方自带的示例项目,名称是struts2-blank-2.1.8.1.war
"struts2-2" 使用的是官方自带的示例项目,名称是struts2-showcase-2.1.8.1.war,我在其中随便选了一个action来做测试
"struts2-3" 同上
"struts2-4" 同上
"struts2-5" 同上
"struts2-6" 同上
"struts2-7" 同上
"struts2-8" 同上
"struts2-9" 同上
未对Struts2做优化,使用的都是官方带的示例,Struts2的测试结果不理想,放在这里做一个参考。“struts2-1”是struts2中测试成绩是本次最高的,但也不十分理想。
测试10:Struts2 官方提供的 示例程序 (使用Struts2标签--s:property) 1192个请求/秒
上一个测试结果糟糕的太离谱了,第二天,想了想又开始重新测试,使用的还是struts2官方提供的struts2-blank-2.1.8.1.war示例。
访问下面的action: http://192.168.0.5/struts2/example/HelloWorld.action ,action内容很简单就是转发到一个JSP。
下图是使用官方示例中默认的action,我没有修改,结果如下图
这里要说一说转发到的jsp中的内容,其中有struts2标签,如下:
Xml代码
- <s:property value="message"/>
- <s:url id="url" action="HelloWorld">
- <s:param name="request_locale">en</s:param>
- </s:url>
- <s:a href="%{url}">English</s:a>
测试11:Struts2 官方提供的 示例程序 (不使用Struts2标签) 1976个请求/秒--优秀啊
我把“测试10”中的jsp文件内容改了,删除了所有的struts2标签,只输出一行文本,测试结果如下图:
天啊,性能超出我的想像,性能太好了,达到了我的要求。看来一定是struts2标签拖了后腿。
测试12:Struts2 官方提供的 示例程序 (使用Struts2标签--s:form) 426个请求/秒
为了让现象复现,我把 “测试10”中 jsp又改了,jsp中换用了其它的struts2标签 ,测试结果如下图:
使用的标签是:
Xml代码
- <s:form action="Login">
- <s:textfield key="username"/>
- <s:password key="password" />
- <s:submit/>
- </s:form>
=====================================================
结论:
struts2框架性能很好, 但struts2的标签性能太差了。 要避免使用 struts2标签。
Struts2 由于采用了 值栈、OGNL表达式、struts2标签库等,会导致性能下降,很严重的下降。如果避免或减少使用这些,性能还是很好的。
Struts2的 多层拦截器、 多实例action性能都很好,并不是 导致性能问题的原因。
注:以上测试都没有数据库,也没有复杂业务,action和jsp中内容很简单,目的就是测试MVC部分的性能。
---------------------------------------------------------------------------------------
其它测试文章:
http://zhaoshg.iteye.com/blog/356231
http://www.iteye.com/topic/679543
MVC框架性能比较
http://wenku.baidu.com/view/148d7e34eefdc8d376ee32ac.html
spring3mvc与struts2比较
http://www.iteye.com/topic/646240
---------------------------------------------------------------------------------------
附:几种标签和框架组合解析数据时候的 性能测试对比
一、 数据
数据通过查询日志表得到数据,共 1302 条数据,将查询出的数据放入一个静态 List 中,保证每次请求的数据相同。
测试页面的元素相同,只是在取数据方式上不同。
二、 测试目标
1、 在 JSP 页面使用 struts2 标签的性能;
2、 在 JSP 页面使用 JSTL 标签的性能;
3、 在 Freemarker 页面使用 struts2 标签的性能;
4、 在 Freemarker 页面使用 JSTL 标签的性能;
5、 在 Freemarker 页面使用其本身的数据加载方式的性能。
三、 加载耗时对比
时间: ms 注:每一次对比都是在同一时间段按同一顺序依次执行下列几种方式
struts2 |
JSTL ( C ) |
Freemarker-struts2 |
Freemarker-C |
Freemarker |
|
第一次 |
306 |
58 |
1618 |
41 |
|
第二次 |
202 |
52 |
1643 |
39 |
|
第三次 |
211 |
58 |
2047 |
36 |
|
第四次 |
196 |
49 |
1621 |
28 |
|
第五次 |
218 |
52 |
1607 |
40 |
|
第六次 |
303 |
331 |
1857 |
45 |
|
第七次 |
210 |
50 |
1671 |
33 |
|
第八次 |
311 |
51 |
1699 |
47 |
|
第九次 |
462 |
55 |
2180 |
37 |
|
第十次 |
218 |
46 |
1721 |
42 |
|
平均值 |
263.7 |
80.2 |
1766.4 |
38.8 |
|
去掉最高和最低 |
223.75 |
53.125 |
1547.125 |
39.125 |