Java MVC框架性能比較
- 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中如下
- <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標簽性能還是不錯的。
- <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,攔截/,所以圖片不能訪問,所以添加了:
- <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標簽,如下:
- <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標簽 ,測試結果如下圖:
使用的標簽是:
- <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 |
