一. 引言
性能測(cè)試與分析是軟件開發(fā)過程中介于架構(gòu)和調(diào)整的一個(gè)廣泛并比較不容易理解的領(lǐng)域,更是一項(xiàng)較為復(fù)雜的活動(dòng)。就像下棋游戲一樣,有效的性能測(cè)試和分析只能在一個(gè)良好的計(jì)劃策略和具備了對(duì)不可預(yù)料事件的處理能力的條件下順利地完成。一個(gè)下棋高手贏得比賽靠的不僅僅是對(duì)游戲規(guī)則的認(rèn)識(shí),更是靠他的自己的能力和不斷地專注于分析自己對(duì)手的實(shí)力來(lái)更加有效地利用和發(fā)揮規(guī)則的作用。同樣一個(gè)優(yōu)秀的性能測(cè)試和分析人員將要面對(duì)的是來(lái)自一個(gè)全新的應(yīng)用程序和環(huán)境下帶來(lái)的整個(gè)項(xiàng)目的挑戰(zhàn)。本文中作者結(jié)合自己的使用經(jīng)驗(yàn)和參考文檔,對(duì)Tomcat性能方面的調(diào)整做一簡(jiǎn)要的介紹,并給出Tomcat性能的測(cè)試、分析和調(diào)整優(yōu)化的一些方法。
二. 測(cè)量Web服務(wù)器的性能
測(cè)量web服務(wù)器的性能是一項(xiàng)讓人感到畏縮的任務(wù),但是我們?cè)谶@里將給出一些需要注意的地方并且指點(diǎn)你了解其中更多的細(xì)節(jié)性的內(nèi)容。它不像一些簡(jiǎn)單的任務(wù),如測(cè)量CPU的速率或者是測(cè)量程序占用CPU的比例,web服務(wù)器的性能優(yōu)化中包括許調(diào)整許多變量來(lái)達(dá)到目標(biāo)。許多的測(cè)量策略中都包含了一個(gè)看似簡(jiǎn)單的瀏覽實(shí)際上是在向服務(wù)器發(fā)送大量的請(qǐng)求,我們稱之為客戶端的程序,來(lái)測(cè)量響應(yīng)時(shí)間。客戶端和服務(wù)器端是在同一臺(tái)機(jī)器上嗎?服務(wù)器在測(cè)試的時(shí)候還運(yùn)行著其它的什么程序嗎?客戶端和服務(wù)器端的通訊是通過局域網(wǎng),100baseT,10baseT還是使用調(diào)制解調(diào)器?客戶端是否一直重復(fù)請(qǐng)求相同的頁(yè)面,還是隨機(jī)地訪問不同的頁(yè)面?(這些影響到了服務(wù)緩存的性能)客戶端發(fā)送請(qǐng)求的有規(guī)律的還是突發(fā)的?你是在最終的配置環(huán)境下運(yùn)行服務(wù)的還是在調(diào)試的配置環(huán)境下運(yùn)行服務(wù)的?客戶端請(qǐng)求中包含圖片還是只有HTML頁(yè)面?是否有請(qǐng)求是通過servlets和JSP的,CGI程序,服務(wù)端包含(Server-Side Includes ,SSI是一個(gè)可以讓你使用動(dòng)態(tài)HTML文件的技術(shù))?所有這些都將是我們要關(guān)心的,并且?guī)缀跷覀儾豢赡芫_地把所有的問題都清楚地列出來(lái)。
1.壓力測(cè)試工具
“工欲善其事,必先利其器”,壓力測(cè)試只有借助于一些工具才可得以實(shí)施。
大多數(shù)web壓力測(cè)試工具的實(shí)現(xiàn)原理都是通過重復(fù)的大量的頁(yè)面請(qǐng)求來(lái)模擬多用戶對(duì)被測(cè)系統(tǒng)的并發(fā)訪問,以此達(dá)到產(chǎn)生壓力的目的。產(chǎn)生壓力的手段都是通過錄制或者是編寫壓力腳本,這些腳本以多個(gè)進(jìn)程或者線程的形式在客戶端運(yùn)行,這樣通過人為制造各種類型的壓力,我們可以觀察被測(cè)系統(tǒng)在各種壓力狀況下的表現(xiàn),從而定位系統(tǒng)瓶頸,作為系統(tǒng)調(diào)優(yōu)的基礎(chǔ)。目前已經(jīng)存在的性能測(cè)試工具林林總總,數(shù)量不下一百種,從單一的開放源碼的免費(fèi)小工具如 Aapache 自帶的 web 性能測(cè)試工具 Apache Benchmark、開源的Jmeter 到大而全的商業(yè)性能測(cè)試軟件如 Mercury 的 LoadRunner 等等。任何性能測(cè)試工具都有其優(yōu)缺點(diǎn),我們可以根據(jù)實(shí)際情況挑選用最合適的工具。您可以在這里找到一些web壓力測(cè)試工具http://www.softwareqatest.com/qatweb1.html#LOAD
這里我們所使用的工具要支持web應(yīng)用服務(wù)認(rèn)證才可以,要支持接收發(fā)送cookies,不僅如此Tomcat支持多種認(rèn)證方式,比如基本認(rèn)證、基于表單的認(rèn)證、相互認(rèn)證和客戶端認(rèn)證,而一些工具僅僅支持HTTP基本認(rèn)證。真實(shí)地模擬用戶認(rèn)證是性能測(cè)試工具的一個(gè)重要的部分,因?yàn)檎J(rèn)證機(jī)制將對(duì)一個(gè)web站點(diǎn)的性能特征產(chǎn)生重要的影響。基于你在產(chǎn)品中使用的不同的認(rèn)證方式,你需要從上面的工具列表中選擇使用這種特性的測(cè)試工具。
Apache Benchmark和http_load是命令行形式的工具,非常易于使用。Apache Benchmark可以模仿單獨(dú)的URL請(qǐng)求并且重復(fù)地執(zhí)行,可以使用不同的命令行參數(shù)來(lái)控制執(zhí)行迭代的次數(shù),并發(fā)用戶數(shù)等等。它的一個(gè)特點(diǎn)是可以周期性地打印出處理過程的信息,而其它工具只能給出一個(gè)全局的報(bào)告。
2.壓力測(cè)試工具介紹
1) Apache Benchmark
下面是運(yùn)行Apache Benchmark的例子,響應(yīng)時(shí)間非常長(zhǎng)是因?yàn)樗\(yùn)行在一個(gè)配置非常低的系統(tǒng)上(Pentium 233)。在這里我們用它來(lái)訪問一個(gè)URL,模擬127個(gè)并發(fā)用戶重復(fù)執(zhí)行1000次。
Root$ ab -k -n 1000 -c 127 -k http://tomcathost:8080/examples/date/date.jsp
This is ApacheBench, Version 2.0.36 <$Revision: 1.1 $> apache-2.0
Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright (c) 1998-2002 The Apache Software Foundation, http://www.apache.org/
Benchmarking tomcathost (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Finished 1000 requests
Server Software: Apache
Server Hostname: tomcathost
Server Port: 8080
Document Path: /examples/date/date.jsp
Document Length: 701 bytes
Concurrency Level: 127
Time taken for tests: 53.162315 seconds
Complete requests: 1000
Failed requests: 0
Write errors: 0
Non-2xx responses: 1000
Keep-Alive requests: 0
Total transferred: 861000 bytes
HTML transferred: 701000 bytes
Requests per second: 18.81[#/sec] (mean)
Time per request: 6.752(mean)
Time per request: 0.053(mean, across all concurrent requests)
Transfer rate: 15.80>ConNECtion Times (ms)
min mean[+/-sd] median max
Connect: 0 51 387.5 0 2999
Processing: 63 6228 2058.4 6208 12072
Waiting: 17 4236 1855.2 3283 9193
Total: 64 6280 2065.0 6285 12072
Percentage of the requests served within a certain time (ms)
50% 6285
66% 6397
75% 6580
80% 9076
90% 9080
95% 9089
98% 9265
99% 12071
100% 12072 (longest request)
2) Apache JMeter 中請(qǐng)求響應(yīng)時(shí)間(圖略)
3) Mercury LoadRunner測(cè)試實(shí)時(shí)監(jiān)控(圖略)
這三個(gè)工具是所有類似性能測(cè)試工具的典型代表,可以根據(jù)你自己的需要選擇不同的測(cè)試工具。這里不對(duì)以上工具做詳細(xì)的介紹,如果您對(duì)這些測(cè)試工具感興趣的話可以參閱附加資料。
3.性能評(píng)測(cè)技巧
1) 由于評(píng)測(cè)時(shí)要用到系統(tǒng)時(shí)鐘,所以當(dāng)進(jìn)行測(cè)試時(shí)不要運(yùn)行無(wú)關(guān)的進(jìn)程或程序,以免影響測(cè)試結(jié)果;
2) 如果對(duì)自己的程序進(jìn)行了修改,并試圖改善它的性能,那么在修改前后應(yīng)分別測(cè)試一下代碼的執(zhí)行時(shí)間;
3) 盡量在完全一致的環(huán)境中進(jìn)行每一次測(cè)試;
4) 如果可能,應(yīng)設(shè)計(jì)一個(gè)不依賴于任何用戶輸入的測(cè)試,測(cè)試中使用的數(shù)據(jù)應(yīng)完全一致,避免用戶的不同的反應(yīng)或者數(shù)據(jù)的問題導(dǎo)致測(cè)試結(jié)果出現(xiàn)誤差;
5) 有可能您還需要考慮是在運(yùn)行著的系統(tǒng)(包括操作系統(tǒng)和被測(cè)試的系統(tǒng))上繼續(xù)進(jìn)行測(cè)試還是重新啟動(dòng)系統(tǒng)后再進(jìn)行測(cè)試;
6) 對(duì)于有些系統(tǒng)第一次使用可能要進(jìn)行初始化,這種工作在系統(tǒng)使用過程中僅進(jìn)行一次,所以有必要在重啟系統(tǒng)后先進(jìn)行一次初始化工作,然后進(jìn)行性能測(cè)試。
三. 外部環(huán)境的調(diào)整
在Tomcat和應(yīng)用程序進(jìn)行了壓力測(cè)試后,如果您對(duì)應(yīng)用程序的性能結(jié)果不太滿意,就可以采取一些性能調(diào)整措施了,當(dāng)然了前提是應(yīng)用程序沒有問題,我們這里只講Tomcat的調(diào)整。由于Tomcat的運(yùn)行依賴于JVM,所以在這里我們把Tomcat的調(diào)整可以分為兩類來(lái)詳細(xì)描述:
外部環(huán)境調(diào)整
調(diào)整非Tomcat組件,例如Tomcat運(yùn)行的操作系統(tǒng)和運(yùn)行Tomcat的java虛擬機(jī)。
自身調(diào)整
修改Tomcat自身的參數(shù),調(diào)整Tomcat配置文件中的參數(shù)。
下面我們將詳細(xì)講解外部環(huán)境調(diào)整的有關(guān)內(nèi)容,Tomcat自身調(diào)整的內(nèi)容將在第2部分中闡述。
1.JAVA虛擬機(jī)性能優(yōu)化
Tomcat本身不能直接在計(jì)算機(jī)上運(yùn)行,需要依賴于硬件基礎(chǔ)之上的操作系統(tǒng)和一個(gè)java虛擬機(jī)。您可以選擇自己的需要選擇不同的操作系統(tǒng)和對(duì)應(yīng)的JDK的版本(只要是符合Sun發(fā)布的Java規(guī)范的),但我們推薦您使用Sun公司發(fā)布的JDK。確保您所使用的版本是最新的,因?yàn)镾un公司和其它一些公司一直在為提高性能而對(duì)java虛擬機(jī)做一些升級(jí)改進(jìn)。一些報(bào)告顯示JDK1.4在性能上比JDK1.3提高了將近10%到20%。
可以給Java虛擬機(jī)設(shè)置使用的內(nèi)存,但是如果你的選擇不對(duì)的話,虛擬機(jī)不會(huì)補(bǔ)償。可通過命令行的方式改變虛擬機(jī)使用內(nèi)存的大小。如下表所示有兩個(gè)參數(shù)用來(lái)設(shè)置虛擬機(jī)使用內(nèi)存的大小。
參數(shù)
描述
-Xms<size>
JVM初始化堆的大小
-Xmx<size>
JVM堆的最大值
這兩個(gè)值的大小一般根據(jù)需要進(jìn)行設(shè)置。初始化堆的大小執(zhí)行了虛擬機(jī)在啟動(dòng)時(shí)向系統(tǒng)申請(qǐng)的內(nèi)存的大小。一般而言,這個(gè)參數(shù)不重要。但是有的應(yīng)用程序在大負(fù)載的情況下會(huì)急劇地占用更多的內(nèi)存,此時(shí)這個(gè)參數(shù)就是顯得非常重要,如果虛擬機(jī)啟動(dòng)時(shí)設(shè)置使用的內(nèi)存比較小而在這種情況下有許多對(duì)象進(jìn)行初始化,虛擬機(jī)就必須重復(fù)地增加內(nèi)存來(lái)滿足使用。由于這種原因,我們一般把-Xms和-Xmx設(shè)為一樣大,而堆的最大值受限于系統(tǒng)使用的物理內(nèi)存。一般使用數(shù)據(jù)量較大的應(yīng)用程序會(huì)使用持久對(duì)象,內(nèi)存使用有可能迅速地增長(zhǎng)。當(dāng)應(yīng)用程序需要的內(nèi)存超出堆的最大值時(shí)虛擬機(jī)就會(huì)提示內(nèi)存溢出,并且導(dǎo)致應(yīng)用服務(wù)崩潰。因此一般建議堆的最大值設(shè)置為可用內(nèi)存的最大值的80%。
Tomcat默認(rèn)可以使用的內(nèi)存為128MB,在較大型的應(yīng)用項(xiàng)目中,這點(diǎn)內(nèi)存是不夠的,需要調(diào)大。
Windows下,在文件{tomcat_home}/bin/catalina.bat,Unix下,在文件{tomcat_home}/bin/catalina.sh的前面,增加如下設(shè)置:
JAVA_OPTS='-Xms【初始化內(nèi)存大小】 -Xmx【可以使用的最大內(nèi)存】'
需要把這個(gè)兩個(gè)參數(shù)值調(diào)大。例如:
JAVA_OPTS='-Xms256m -Xmx512m'
表示初始化內(nèi)存為256MB,可以使用的最大內(nèi)存為512MB。
另外需要考慮的是Java提供的垃圾回收機(jī)制。虛擬機(jī)的堆大小決定了虛擬機(jī)花費(fèi)在收集垃圾上的時(shí)間和頻度。收集垃圾可以接受的速度與應(yīng)用有關(guān),應(yīng)該通過分析實(shí)際的垃圾收集的時(shí)間和頻率來(lái)調(diào)整。如果堆的大小很大,那么完全垃圾收集就會(huì)很慢,但是頻度會(huì)降低。如果你把堆的大小和內(nèi)存的需要一致,完全收集就很快,但是會(huì)更加頻繁。調(diào)整堆大小的的目的是最小化垃圾收集的時(shí)間,以在特定的時(shí)間內(nèi)最大化處理客戶的請(qǐng)求。在基準(zhǔn)測(cè)試的時(shí)候,為保證最好的性能,要把堆的大小設(shè)大,保證垃圾收集不在整個(gè)基準(zhǔn)測(cè)試的過程中出現(xiàn)。
如果系統(tǒng)花費(fèi)很多的時(shí)間收集垃圾,請(qǐng)減小堆大小。一次完全的垃圾收集應(yīng)該不超過 3-5 秒。如果垃圾收集成為瓶頸,那么需要指定代的大小,檢查垃圾收集的詳細(xì)輸出,研究 垃圾收集參數(shù)對(duì)性能的影響。一般說來(lái),你應(yīng)該使用物理內(nèi)存的 80% 作為堆大小。當(dāng)增加處理器時(shí),記得增加內(nèi)存,因?yàn)榉峙淇梢圆⑿羞M(jìn)行,而垃圾收集不是并行的。
2.操作系統(tǒng)性能優(yōu)化
這里說的操作系統(tǒng)是指運(yùn)行web服務(wù)器的系統(tǒng)軟件,當(dāng)然,不同的操作系統(tǒng)是為不同的目的而設(shè)計(jì)的。比如OpenBSD是面向安全的,因此在它的內(nèi)核中有許多的限制來(lái)防止不同形式的服務(wù)攻擊(OpenBSD的一句座右銘是“默認(rèn)是最安全的”)。這些限制或許更多地用來(lái)運(yùn)行活躍的web服務(wù)器。
而我們常用的Linux操作系統(tǒng)的目標(biāo)是易用使用,因此它有著更高的限制。使用BSD內(nèi)核的系統(tǒng)都帶有一個(gè)名為“Generic”的內(nèi)核,表明所有的驅(qū)動(dòng)器都靜態(tài)地與之相連。這樣就使系統(tǒng)易于使用,但是如果你要?jiǎng)?chuàng)建一個(gè)自定義的內(nèi)核來(lái)加強(qiáng)其中某些限制,那就需要排除不需要的設(shè)備。Linux內(nèi)核中的許多驅(qū)動(dòng)都是動(dòng)態(tài)地加載的。但是換而言之,內(nèi)存現(xiàn)在變得越來(lái)越便宜,所以因?yàn)榧虞d額外的設(shè)備驅(qū)動(dòng)就顯得不是很重要的。重要的是要有更多的內(nèi)存,并且在服務(wù)器上騰出更多的可用內(nèi)存。
小提示:雖然現(xiàn)在內(nèi)存已經(jīng)相當(dāng)?shù)谋阋耍€是盡量不要購(gòu)買便宜的內(nèi)存。那些有牌子的內(nèi)存雖然是貴一點(diǎn),但是從可靠性上來(lái)說,性價(jià)比會(huì)更高一些。
如果是在Windows操作系統(tǒng)上使用Tomcat,那么最好選擇服務(wù)器版本。因?yàn)樵诜欠?wù)器版本上,最終用戶授權(quán)數(shù)或者操作系統(tǒng)本身所能承受的用戶數(shù)、可用的網(wǎng)絡(luò)連接數(shù)或其它方面的一些方面都是有限制的。并且基于安全性的考慮,必須經(jīng)常給操作系統(tǒng)打上最新的補(bǔ)丁。
3.Tomcat與其它web服務(wù)器整合使用
雖然tomcat也可以作web服務(wù)器,但其處理靜態(tài)html的速度比不上apache,且其作為web服務(wù)器的功能遠(yuǎn)不如apache,因此我們想把a(bǔ)pache和tomcat集成起來(lái),將html與jsp的功能部分進(jìn)行明確分工,讓tomcat只處理jsp部分,其它的由apache,IIS等這些web服務(wù)器處理,由此大大節(jié)省了tomcat有限的工作“線程”。
4.負(fù)載均衡
在負(fù)載均衡的思路下,多臺(tái)服務(wù)器為對(duì)稱方式,每臺(tái)服務(wù)器都具有同等的地位,可以單獨(dú)對(duì)外提供服務(wù)而無(wú)須其他服務(wù)器的輔助。通過負(fù)載分擔(dān)技術(shù),將外部發(fā)送來(lái)的請(qǐng)求按一定規(guī)則分配到對(duì)稱結(jié)構(gòu)中的某一臺(tái)服務(wù)器上,而接收到請(qǐng)求的服務(wù)器都獨(dú)立回應(yīng)客戶機(jī)的請(qǐng)求。
提供服務(wù)的一組服務(wù)器組成了一個(gè)應(yīng)用服務(wù)器集群(cluster),并對(duì)外提供一個(gè)統(tǒng)一的地址。當(dāng)一個(gè)服務(wù)請(qǐng)求被發(fā)至該集群時(shí),根據(jù)一定規(guī)則選擇一臺(tái)服務(wù)器,并將服務(wù)轉(zhuǎn)定向給該服務(wù)器承擔(dān),即將負(fù)載進(jìn)行均衡分?jǐn)偂?
通過應(yīng)用負(fù)載均衡技術(shù),使應(yīng)用服務(wù)超過了一臺(tái)服務(wù)器只能為有限用戶提供服務(wù)的限制,可以利用多臺(tái)服務(wù)器同時(shí)為大量用戶提供服務(wù)。當(dāng)某臺(tái)服務(wù)器出現(xiàn)故障時(shí),負(fù)載均衡服務(wù)器會(huì)自動(dòng)進(jìn)行檢測(cè)并停止將服務(wù)請(qǐng)求分發(fā)至該服務(wù)器,而由其他工作正常的服務(wù)器繼續(xù)提供服務(wù),從而保證了服務(wù)的可靠性。
負(fù)載均衡實(shí)現(xiàn)的方式大概有四種:第一是通過DNS,但只能實(shí)現(xiàn)簡(jiǎn)單的輪流分配,不能處理故障,第二如果是基于MS IIS,Windows 2003 server本身就帶了負(fù)載均衡服務(wù),第三是硬件方式,通過交換機(jī)的功能或?qū)iT的負(fù)載均衡設(shè)備可以實(shí)現(xiàn),第四種是軟件方式,通過一臺(tái)負(fù)載均衡服務(wù)器進(jìn)行,上面安裝軟件。使用Apache Httpd Server做負(fù)載平衡器,Tomcat集群節(jié)點(diǎn)使用Tomcat就可以做到以上第四種方式。這種方式比較靈活,成本相對(duì)也較低。另外一個(gè)很大的優(yōu)點(diǎn)就是可以根據(jù)應(yīng)用的情況和服務(wù)器的情況采取一些策略。
四. 自身調(diào)整
本節(jié)將向您詳細(xì)介紹一些加速可使Tomcat實(shí)例加速運(yùn)行的技巧和方法,無(wú)論是在什么操作系統(tǒng)或者何種Java虛擬機(jī)上。在有些情況下,您可能沒有控制部署環(huán)境上的操作系統(tǒng)或者Java虛擬機(jī)。在這種情況下,您就需要逐行了解以下的的一些建議,然而你應(yīng)該在修改后使之生效。我認(rèn)為以下方法是Tomcat性能自身調(diào)整的最佳方式。
1.禁用DNS查詢
當(dāng)web應(yīng)用程序向要記錄客戶端的信息時(shí),它也會(huì)記錄客戶端的IP地址或者通過域名服務(wù)器查找機(jī)器名轉(zhuǎn)換為IP地址。DNS查詢需要占用網(wǎng)絡(luò),并且包括可能從很多很遠(yuǎn)的服務(wù)器或者不起作用的服務(wù)器上去獲取對(duì)應(yīng)的IP的過程,這樣會(huì)消耗一定的時(shí)間。為了消除DNS查詢對(duì)性能的影響我們可以關(guān)閉DNS查詢,方式是修改server.xml文件中的enableLookups參數(shù)值:
Tomcat4
<Connector className="org.apache.coyote.tomcat4.CoyoteConnector" port="80" minProcessors="5" maxProcessors="75" enableLookups="false" redirectPort="8443" acceptCount="100" debug="0" connectionTimeout="20000" useURIValidationHack="false" disableUploadTimeout="true" />
Tomcat5
<Connector port="80" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" redirectPort="8443" acceptCount="100" debug="0" connectionTimeout="20000" disableUploadTimeout="true"/>
除非你需要連接到站點(diǎn)的每個(gè)HTTP客戶端的機(jī)器名,否則我們建議在生產(chǎn)環(huán)境上關(guān)閉DNS查詢功能。可以通過Tomcat以外的方式來(lái)獲取機(jī)器名。這樣不僅節(jié)省了網(wǎng)絡(luò)帶寬、查詢時(shí)間和內(nèi)存,而且更小的流量會(huì)使日志數(shù)據(jù)也會(huì)變得更少,顯而易見也節(jié)省了硬盤空間。對(duì)流量較小的站點(diǎn)來(lái)說禁用DNS查詢可能沒有大流量站點(diǎn)的效果明顯,但是此舉仍不失為一良策。誰(shuí)又見到一個(gè)低流量的網(wǎng)站一夜之間就流量大增呢?
2.調(diào)整線程數(shù)
另外一個(gè)可通過應(yīng)用程序的連接器(Connector)進(jìn)行性能控制的的參數(shù)是創(chuàng)建的處理請(qǐng)求的線程數(shù)。Tomcat使用線程池加速響應(yīng)速度來(lái)處理請(qǐng)求。在Java中線程是程序運(yùn)行時(shí)的路徑,是在一個(gè)程序中與其它控制線程無(wú)關(guān)的、能夠獨(dú)立運(yùn)行的代碼段。它們共享相同的地址空間。多線程幫助程序員寫出CPU最大利用率的高效程序,使空閑時(shí)間保持最低,從而接受更多的請(qǐng)求。
Tomcat4中可以通過修改minProcessors和maxProcessors的值來(lái)控制線程數(shù)。這些值在安裝后就已經(jīng)設(shè)定為默認(rèn)值并且是足夠使用的,但是隨著站點(diǎn)的擴(kuò)容而改大這些值。minProcessors服務(wù)器啟動(dòng)時(shí)創(chuàng)建的處理請(qǐng)求的線程數(shù)應(yīng)該足夠處理一個(gè)小量的負(fù)載。也就是說,如果一天內(nèi)每秒僅發(fā)生5次單擊事件,并且每個(gè)請(qǐng)求任務(wù)處理需要1秒鐘,那么預(yù)先設(shè)置線程數(shù)為5就足夠了。但在你的站點(diǎn)訪問量較大時(shí)就需要設(shè)置更大的線程數(shù),指定為參數(shù)maxProcessors的值。maxProcessors的值也是有上限的,應(yīng)防止流量不可控制(或者惡意的服務(wù)攻擊),從而導(dǎo)致超出了虛擬機(jī)使用內(nèi)存的大小。如果要加大并發(fā)連接數(shù),應(yīng)同時(shí)加大這兩個(gè)參數(shù)。web server允許的最大連接數(shù)還受制于操作系統(tǒng)的內(nèi)核參數(shù)設(shè)置,通常Windows是2000個(gè)左右,Linux是1000個(gè)左右。
在Tomcat5對(duì)這些參數(shù)進(jìn)行了調(diào)整,請(qǐng)看下表:
屬性名
描述
maxThreads
Tomcat使用線程來(lái)處理接收的每個(gè)請(qǐng)求。這個(gè)值表示Tomcat可創(chuàng)建的最大的線程數(shù)。
acceptCount
指定當(dāng)所有可以使用的處理請(qǐng)求的線程數(shù)都被使用時(shí),可以放到處理隊(duì)列中的請(qǐng)求數(shù),超過這個(gè)數(shù)的請(qǐng)求將不予處理。
connnectionTimeout
網(wǎng)絡(luò)連接超時(shí),單位:毫秒。設(shè)置為0表示永不超時(shí),這樣設(shè)置有隱患的。通常可設(shè)置為30000毫秒。
minSpareThreads
Tomcat初始化時(shí)創(chuàng)建的線程數(shù)。
maxSpareThreads
一旦創(chuàng)建的線程超過這個(gè)值,Tomcat就會(huì)關(guān)閉不再需要的socket線程。
最好的方式是多設(shè)置幾次并且進(jìn)行測(cè)試,觀察響應(yīng)時(shí)間和內(nèi)存使用情況。在不同的機(jī)器、操作系統(tǒng)或虛擬機(jī)組合的情況下可能會(huì)不同,而且并不是所有人的web站點(diǎn)的流量都是一樣的,因此沒有一刀切的方案來(lái)確定線程數(shù)的值。
3.加速JSP編譯速度
當(dāng)?shù)谝淮卧L問一個(gè)JSP文件時(shí),它會(huì)被轉(zhuǎn)換為Java serverlet源碼,接著被編譯成Java字節(jié)碼。你可以控制使用哪個(gè)編譯器,默認(rèn)情況下,Tomcat使用使用命令行javac進(jìn)行使用的編譯器。也可以使用更快的編譯器,但是這里我們將介紹如何優(yōu)化它們。
另外一種方法是不要把所有的實(shí)現(xiàn)都使用JSP頁(yè)面,而是使用一些不同的java模板引擎變量。顯然這是一個(gè)跨越很大的決定,但是事實(shí)證明至少這種方法是只得研究的。如果你想了解更多有關(guān)在Tomcat可使用的模板語(yǔ)言,你可以參考Jason Hunter和William Crawford合著的《Java Servlet Programming 》一書(O'Reilly公司出版)。
在Tomcat 4.0中可以使用流行而且免費(fèi)的Jikes編譯器。Jikes編譯器的速度要由于Sun的Java編譯器。首先要安裝Jikes(可訪問http://oss.software.ibm.com/pub/jikes 獲得更多的信息),接著需要在環(huán)境變量中設(shè)置JIKESPATH包含系統(tǒng)運(yùn)行時(shí)所需的JAR文件。裝好Jikes以后還需要設(shè)置讓JSP編譯servlet使用Jikes,需要修改web.xml文件中jspCompilerPlugin的值:
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>
org.apache.jasper.servlet.JspServlet
</servlet-class>
<init-param>
<param-name>logVerbosityLevel</param-name>
<param-value>WARNING</param-value>
</init-param>
<init-param>
<param-name>jspCompilerPlugin</param-name>
<param-value>
org.apache.jasper.compiler.JikesJavaCompiler
</param-value>
</init-param>
<init-param>
<!-- <param-name>
org.apache.catalina.jsp_classpath
</param-name> -->
<param-name>classpath</param-name>
<param-value>
/usr/local/jdk1.3.1-linux/jre/lib/rt.jar:
/usr/local/lib/java/servletapi/servlet.ja
r</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
在Tomcat 4.1(或更高版本),JSP的編譯由包含在Tomcat里面的Ant程序控制器直接執(zhí)行。這聽起來(lái)有一點(diǎn)點(diǎn)奇怪,但這正是Ant有意為之的一部分,有一個(gè)API文檔指導(dǎo)開發(fā)者在沒有啟動(dòng)一個(gè)新的JVM的情況下,使用Ant。這是使用Ant進(jìn)行Java開發(fā)的一大優(yōu)勢(shì)。另外,這也意味著你現(xiàn)在能夠在Ant中使用任何javac支持的編譯方式,這里有一個(gè)關(guān)于Apache Ant使用手冊(cè)的javac page列表。使用起來(lái)是容易的,因?yàn)槟阒恍枰?元素中定義一個(gè)名字叫“compiler”,并且在value中有一個(gè)支持編譯的編譯器名字,示例如下:
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>
org.apache.jasper.servlet.JspServlet
</servlet-class>
<init-param>
<param-name>logVerbosityLevel</param-name>
<param-value>WARNING</param-value>
</init-param>
<init-param>
<param-name>compiler</param-name>
<param-value>jikes</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
Ant可用的編譯器
名稱
別名
調(diào)用的編譯器
classic
javac1.1, javac1.2
Standard JDK 1.1/1.2 compiler
modern
javac1.3, javac1.4
Standard JDK 1.3/1.4 compiler
jikes
The Jikes compiler
JVC microsoft
Microsoft command-line compiler from the Microsoft SDK for Java/Visual J++
KJC The kopi compiler
GCJ The gcj compiler (included as part of gcc)
SJ Symantec
Symantec's Java compiler
extJavac
Runs either the modern or classic compiler in a JVM of its own
由于JSP頁(yè)面在第一次使用時(shí)已經(jīng)被編譯,那么你可能希望在更新新的jsp頁(yè)面后馬上對(duì)它進(jìn)行編譯。實(shí)際上,這個(gè)過程完全可以自動(dòng)化,因?yàn)榭梢源_認(rèn)的是新的JSP頁(yè)面在生產(chǎn)服務(wù)器和在測(cè)試服務(wù)器上的運(yùn)行效果是一樣的。
在Tomcat4的bin目錄下有一個(gè)名為jspc的腳本。它僅僅是運(yùn)行翻譯階段,而不是編譯階段,使用它可以在當(dāng)前目錄生成Java源文件。它是調(diào)試JSP頁(yè)面的一種有力的手段。
可以通過瀏覽器訪問再確認(rèn)一下編譯的結(jié)果。這樣就確保了文件被轉(zhuǎn)換成serverlet,被編譯了可直接執(zhí)行。這樣也準(zhǔn)確地模仿了真實(shí)用戶訪問JSP頁(yè)面,可以看到給用戶提供的功能。也抓緊這最后一刻修改出現(xiàn)的bug并且修改它J
Tomcat提供了一種通過請(qǐng)求來(lái)編譯JSP頁(yè)面的功能。例如,你可以在瀏覽器地址欄中輸入http://localhost:8080/examples/jsp/dates/date.jsp?jsp_precompile=true,這樣Tomcat就會(huì)編譯data.jsp而不是執(zhí)行它。此舉唾手可得,不失為一種檢驗(yàn)頁(yè)面正確性的捷徑。
4. 其它
前面我們提到過操作系統(tǒng)通過一些限制手段來(lái)防止惡意的服務(wù)攻擊,同樣Tomcat也提供了防止惡意攻擊或禁止某些機(jī)器訪問的設(shè)置。
Tomcat提供了兩個(gè)參數(shù)供你配置:RemoteHostValve 和RemoteAddrValve。
通過配置這兩個(gè)參數(shù),可以讓你過濾來(lái)自請(qǐng)求的主機(jī)或IP地址,并允許或拒絕哪些主機(jī)/IP。與之類似的,在Apache的httpd文件里有對(duì)每個(gè)目錄的允許/拒絕指定。
例如你可以把Admin Web application設(shè)置成只允許本地訪問,設(shè)置如下:
<Context path="/path/to/secret_files" ...>
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="127.0.0.1" deny=""/>
</Context>
如果沒有給出允許主機(jī)的指定,那么與拒絕主機(jī)匹配的主機(jī)就會(huì)被拒絕,除此之外的都是允許的。與之類似,如果沒有給出拒絕主機(jī)的指定,那么與允許主機(jī)匹配的主機(jī)就會(huì)被允許,除此之外的都是拒絕的。
五. 容量計(jì)劃
容量計(jì)劃是在生產(chǎn)環(huán)境中使用Tomcat不得不提的提高性能的另一個(gè)重要的話題。如果你沒有對(duì)預(yù)期的網(wǎng)絡(luò)流量下的硬件和帶寬做考慮的話那么無(wú)論你如何做配置修改和測(cè)試都無(wú)濟(jì)于事。
這里先對(duì)提及的容量計(jì)劃作一個(gè)簡(jiǎn)要的定義:容量計(jì)劃是指評(píng)估硬件、操作系統(tǒng)和網(wǎng)絡(luò)帶寬,確定應(yīng)用服務(wù)的服務(wù)范圍,尋求適合需求和軟件特性的軟硬件的一項(xiàng)活動(dòng)。因此這里所說的軟件不僅包括Tomcat,也包括與Tomcat結(jié)合使用的任何第三方web服務(wù)器軟件。
如果在購(gòu)買軟硬件或部署系統(tǒng)前你對(duì)容量計(jì)劃一無(wú)所知,不知道現(xiàn)有的軟硬件環(huán)境能夠支撐多少的訪問量,甚至更糟直到你已經(jīng)交付并且在生產(chǎn)環(huán)境上部署產(chǎn)品后才意識(shí)到配置有問題時(shí)再進(jìn)行變更可能為時(shí)已晚。此時(shí)只能增加硬件投入,增加硬盤容量甚至購(gòu)買更好的服務(wù)器。如果事先做了容量計(jì)劃那么就不會(huì)搞的如此焦頭爛額了。
我們這里只介紹與Tomcat相關(guān)的內(nèi)容。
首先為了確定Tomcat使用機(jī)器的容量計(jì)劃,你應(yīng)該從一下列表項(xiàng)目種著手研究和計(jì)劃:
1. 硬件
采用什么樣的硬件體系?需要多少臺(tái)計(jì)算機(jī)?使用一個(gè)大型的,還是使用多臺(tái)小型機(jī)?每個(gè)計(jì)算機(jī)上使用幾個(gè)CPU?使用多少內(nèi)存?使用什么樣的存儲(chǔ)設(shè)備,I/O的處理速度有什么要求?怎樣維護(hù)這些計(jì)算機(jī)?不同的JVM在這些硬件上運(yùn)行的效果如何(比如IBM AIX系統(tǒng)只能在其設(shè)計(jì)的硬件系統(tǒng)上運(yùn)行)?
2. 網(wǎng)絡(luò)帶寬
帶寬的使用極限是多少?web應(yīng)用程序如何處理過多的請(qǐng)求?
3. 服務(wù)端操作系統(tǒng)
采用哪種操作系統(tǒng)作為站點(diǎn)服務(wù)器最好?在確定的操作系統(tǒng)上使用哪個(gè)JVM最好?例如,JVM在這種系統(tǒng)上是否支持本地多線程,對(duì)稱多處理?哪種系統(tǒng)可使web服務(wù)器更快、更穩(wěn)定,并且更便宜。是否支持多CPU?
4. Tomcat容量計(jì)劃
以下介紹針對(duì)Tomcat做容量計(jì)劃的步驟:
1) 量化負(fù)載。如果站點(diǎn)已經(jīng)建立并運(yùn)行,可以使用前面介紹的工具模仿用戶訪問,確定資源的需求量。
2) 針對(duì)測(cè)試結(jié)果或測(cè)試過程中進(jìn)行分析。需要知道那些請(qǐng)求造成了負(fù)載過重或者使用過多的資源,并與其它請(qǐng)求做比較,這樣就確定了系統(tǒng)的瓶頸所在。例如:如果servlet在查詢數(shù)據(jù)庫(kù)的步驟上耗用較長(zhǎng)的時(shí)間,那么就需要考慮使用緩沖池來(lái)降低響應(yīng)時(shí)間。
3) 確定性能最低標(biāo)準(zhǔn)。例如,你不想讓用戶花20秒來(lái)等待結(jié)果頁(yè)面的返回,也就是說甚至在達(dá)到訪問量的極限時(shí),用戶等待的時(shí)間也不能超過20秒種(從點(diǎn)擊鏈接到看到返第一條返回?cái)?shù)據(jù))。這個(gè)時(shí)間中包含了數(shù)據(jù)庫(kù)查詢時(shí)間和文件訪問時(shí)間。同類產(chǎn)品性能在不同的公司可能有不同的標(biāo)準(zhǔn),一般最好采取同行中的最低標(biāo)準(zhǔn)或?qū)@個(gè)標(biāo)準(zhǔn)做出評(píng)估。
4) 確定如何合理使用底層資源,并逐一進(jìn)行測(cè)試。底層資源包括CPU、內(nèi)存、存儲(chǔ)器、帶寬、操作系統(tǒng)、JVM等等。在各種生產(chǎn)環(huán)境上都按順序進(jìn)行部署和測(cè)試,觀察是否符合需求。在測(cè)試Tomcat時(shí)盡量多采用幾種JVM,并且調(diào)整JVM使用內(nèi)存和Tomcat線程池的大小進(jìn)行測(cè)試。同時(shí)為了達(dá)到資源充分合理穩(wěn)定地使用的效果,還需針對(duì)測(cè)試過程中出現(xiàn)的硬件系統(tǒng)瓶頸進(jìn)行處理確定合理的資源配置。這個(gè)過程最為復(fù)雜,而且一般由于沒有可參考的值所以只能靠理論推斷和經(jīng)驗(yàn)總結(jié)。
5) 如果通過第4步的反復(fù)測(cè)試如果達(dá)到了最優(yōu)的組合,就可以在相同的生產(chǎn)環(huán)境上部署產(chǎn)品了。
此外應(yīng)牢記一定要文檔化你的測(cè)試過程和結(jié)果,因?yàn)榇撕罂赡苓€會(huì)進(jìn)行測(cè)試,這樣就可以拿以前的測(cè)試結(jié)果做為參考。另外測(cè)試過程要反復(fù)多次進(jìn)行,每次的條件可能都不一樣,因此只有記錄下來(lái)才能進(jìn)行結(jié)果比較和最佳條件的選擇。
這樣我們通過測(cè)試找到了最好的組合方式,各種資源得到了合理的配置,系統(tǒng)的性能得到了極大的提升。
六. 附加資料
很顯然本文也很難全面而詳盡地闡述性能優(yōu)化過程。如果你進(jìn)行更多研究的話可能會(huì)把性能調(diào)優(yōu)做的更好,比如Java程序的性能調(diào)整、操作系統(tǒng)的調(diào)整、各種復(fù)雜環(huán)境與應(yīng)用系統(tǒng)和其它所有與應(yīng)用程序相關(guān)的東西。在這里提供一些文中提到的一些資源、文中提到的相關(guān)內(nèi)容的鏈接以及本文的一些參考資料。
1. Web性能測(cè)試資料及工具
1) Jmeter Wiki首頁(yè),Jmeter為一個(gè)開源的100%Java開發(fā)的性能測(cè)試工具
http://wiki.apache.org/jakarta-jmeter/
2) Apache Benchmark使用說明
http://httpd.apache.org/docs-2.0/programs/ab.html
3) 一些Java相關(guān)測(cè)試工具的介紹,包含可以與Tomcat集成進(jìn)行測(cè)試的工具
http://blog.csdn.net/wyingquan/
4) LoadRunner? 是一種預(yù)測(cè)系統(tǒng)行為和性能的工業(yè)標(biāo)準(zhǔn)級(jí)負(fù)載測(cè)試工具。它通過模擬數(shù)據(jù)以千萬(wàn)計(jì)用戶來(lái)實(shí)施并發(fā)負(fù)載來(lái)對(duì)整個(gè)企業(yè)架構(gòu)進(jìn)行測(cè)試,來(lái)幫助您更快的查找和發(fā)現(xiàn)問題。
http://www.mercury.com/us/products/performance-center/loadrunner/
2. 文中介紹的相關(guān)內(nèi)容的介紹
1) Apache 2.x + Tomcat 4.x做負(fù)載均衡,描述了如何利用jk配置集群的負(fù)載均衡。
http://raibledesigns.com/tomcat/index.html
2) 容量計(jì)劃的制定,收集了許多有關(guān)制定web站點(diǎn)容量計(jì)劃的例子:
http://www.capacityplanning.com/
3) 評(píng)測(cè)Tomcat5負(fù)載平衡與集群,
http://www.javaresearch.org/article/showarticle.jsp?column=556&thread=19777
4) Apache與Tomcat的安裝與整合之整合篇
http://www.javaresearch.org/article/showarticle.jsp?column=23&thread=18139
5) 性能測(cè)試工具之研究,介紹了性能測(cè)試工具的原理與思路
http://www.51testing.com/emagzine/no2_2.htm
6) Java的內(nèi)存泄漏
http://www.matrix.org.cn/resource/article/409.html
7) Web服務(wù)器和應(yīng)用程序服務(wù)器有什么區(qū)別?
http://www.matrix.org.cn/resource/article/1429.html
8) 詳細(xì)講解性能中數(shù)據(jù)庫(kù)集群的問題
http://www.theserverside.com/articles/article.tss?l=db_break