1. 程式人生 > >Tomcat優化及壓力測試例項 .

Tomcat優化及壓力測試例項 .

在 Tomcat和應用程式進行了壓力測試後,如果您對應用程式的效能結果不太滿意,就可以採取一些效能調整措施了,當然了前提是應用程式沒有問題,

我們這裡 只講Tomcat的調整。由於Tomcat的執行依賴於JVM,所以在這裡我們把Tomcat的調整可以分為兩類來詳細描述:

外部環境調整

  調整非Tomcat元件,例如Tomcat執行的作業系統和執行Tomcat的java虛擬機器。

自身調整

  修改Tomcat自身的引數,調整Tomcat配置檔案中的引數。

下面我們將詳細講解外部環境調整的有關內容,Tomcat自身調整的內容將在第2部分中闡述。

  1.JAVA虛擬機器效能優化

  Tomcat本身不能直接在計算機上執行,需要依賴於硬體基礎之上的作業系統和一個java虛擬機器。您可以選擇自己的需要選擇不同的作業系統和 對應的JDK的版本(只要是符合Sun釋出的Java規範的),但我們推薦您使用Sun公司釋出的JDK。確保您所使用的版本是最新的,因為Sun公司和 其它一些公司一直在為提高效能而對java虛擬機器做一些升級改進。一些報告顯示JDK1.4在效能上比JDK1.3提高了將近10%到20%。

  可以給Java虛擬機器設定使用的記憶體,但是如果你的選擇不對的話,虛擬機器不會補償。可通過命令列的方式改變虛擬機器使用記憶體的大小。

 如下表所示有兩個引數用來設定虛擬機器使用記憶體的大小。 

   引數   描述

  -Xms<size> 
 JVM初始化堆的大小

 -Xmx<size> 
 JVM堆的最大值

這兩個值的大小一般根據需要進行設定。初始化堆的大小執行了虛擬機器在啟動時向系統申請的記憶體的大小。一般而言,這個引數不重要。但是有的應用程 序在大負載的情況下會急劇地佔用更多的記憶體,此時這個引數就是顯得非常重要,如果虛擬機器啟動時設定使用的記憶體比較小而在這種情況下有許多物件進行初始化, 虛擬機器就必須重複地增加記憶體來滿足使用。由於這種原因,我們一般把-Xms和-Xmx設為一樣大,而堆的最大值受限於系統使用的實體記憶體。一般使用資料量 較大的應用程式會使用持久物件,記憶體使用有可能迅速地增長。當應用程式需要的記憶體超出堆的最大值時虛擬機器就會提示記憶體溢位,並且導致應用服務崩潰。因此一 般建議堆的最大值設定為可用記憶體的最大值的80%。

  Tomcat預設可以使用的記憶體為128MB,在較大型的應用專案中,這點記憶體是不夠的,需要調大。

  Windows下,在檔案{tomcat_home}/bin/catalina.bat,Unix下,在檔案{tomcat_home}/bin/catalina.sh的前面,增加如下設定:

  JAVA_OPTS='-Xms【初始化記憶體大小】 -Xmx【可以使用的最大記憶體】'

  需要把這個兩個引數值調大。例如:

  JAVA_OPTS='-Xms256m -Xmx512m'

  表示初始化記憶體為256MB,可以使用的最大記憶體為512MB。

  另外需要考慮的是Java提供的垃圾回收機制。虛擬機器的堆大小決定了虛擬機器花費在收集垃圾上的時間和頻度。收集垃圾可以接受的速度與應用有關, 應該通過分析實際的垃圾收集的時間和頻率來調整。如果堆的大小很大,那麼完全垃圾收集就會很慢,但是頻度會降低。如果你把堆的大小和記憶體的需要一致,完全 收集就很快,但是會更加頻繁。調整堆大小的的目的是最小化垃圾收集的時間,以在特定的時間內最大化處理客戶的請求。在基準測試的時候,為保證最好的效能, 要把堆的大小設大,保證垃圾收集不在整個基準測試的過程中出現。

  如果系統花費很多的時間收集垃圾,請減小堆大小。一次完全的垃圾收集應該不超過 3-5 秒。如果垃圾收整合為瓶頸,那麼需要指定代的大小,檢查垃圾收集的詳細輸出,研究 垃圾收集引數對效能的影響。一般說來,你應該使用實體記憶體的 80% 作為堆大小。當增加處理器時,記得增加記憶體,因為分配可以並行進行,而垃圾收集不是並行的。

2.作業系統效能優化

  這裡說的作業系統是指執行web伺服器的系統軟體,當然,不同的作業系統是為不同的目的而設計的。比如OpenBSD是面向安全的,因此在它的 核心中有許多的限制來防止不同形式的服務攻擊(OpenBSD的一句座右銘是“預設是最安全的”)。這些限制或許更多地用來執行活躍的web伺服器。

  而我們常用的Linux作業系統的目標是易用使用,因此它有著更高的限制。使用BSD核心的系統都帶有一個名為“Generic”的核心,表明 所有的驅動器都靜態地與之相連。這樣就使系統易於使用,但是如果你要建立一個自定義的核心來加強其中某些限制,那就需要排除不需要的裝置。Linux核心 中的許多驅動都是動態地載入的。但是換而言之,記憶體現在變得越來越便宜,所以因為載入額外的裝置驅動就顯得不是很重要的。重要的是要有更多的記憶體,並且在 伺服器上騰出更多的可用記憶體。

  小提示:雖然現在記憶體已經相當的便宜,但還是儘量不要購買便宜的記憶體。那些有牌子的記憶體雖然是貴一點,但是從可靠性上來說,價效比會更高一些。

  如果是在Windows作業系統上使用Tomcat,那麼最好選擇伺服器版本。因為在非伺服器版本上,終端使用者授權數或者作業系統本身所能承受的使用者數、可用的網路連線數或其它方面的一些方面都是有限制的。並且基於安全性的考慮,必須經常給作業系統打上最新的補丁。

3.Tomcat與其它web伺服器整合使用

  雖然tomcat也可以作web伺服器,但其處理靜態html的速度比不上apache,且其作為web伺服器的功能遠不如apache,因此 我們想把apache和tomcat整合起來,將html與jsp的功能部分進行明確分工,讓tomcat只處理jsp部分,其它的由apache, IIS等這些web伺服器處理,由此大大節省了tomcat有限的工作“執行緒”。

 4.負載均衡

  在負載均衡的思路下,多臺伺服器為對稱方式,每臺伺服器都具有同等的地位,可以單獨對外提供服務而無須其他伺服器的輔助。通過負載分擔技術,將外部發送來的請求按一定規則分配到對稱結構中的某一臺伺服器上,而接收到請求的伺服器都獨立迴應客戶機的請求。

  提供服務的一組伺服器組成了一個應用伺服器叢集(cluster),並對外提供一個統一的地址。當一個服務請求被髮至該叢集時,根據一定規則選擇一臺伺服器,並將服務轉定向給該伺服器承擔,即將負載進行均衡分攤。

  通過應用負載均衡技術,使應用服務超過了一臺伺服器只能為有限使用者提供服務的限制,可以利用多臺伺服器同時為大量使用者提供服務。當某臺伺服器出 現故障時,負載均衡伺服器會自動進行檢測並停止將服務請求分發至該伺服器,而由其他工作正常的伺服器繼續提供服務,從而保證了服務的可靠性。

  負載均衡實現的方式大概有四種:第一是通過DNS,但只能實現簡單的輪流分配,不能處理故障,第二如果是基於MS IIS, Windows 2003 server本身就帶了負載均衡服務,第三是硬體方式,通過交換機的功能或專門的負載均衡裝置可以實現,第四種是軟體方式,通過一臺負載均衡伺服器進行, 上面安裝軟體。使用Apache Httpd Server做負載平衡器,Tomcat叢集節點使用Tomcat就可以做到以上第四種方式。這種方式比較靈活,成本相對也較低。另外一個很大的優點就是 可以根據應用的情況和伺服器的情況採取一些策略。

大家都知道,JAVA程式啟動時都會JVM都會分配一個初始記憶體和最大記憶體給這個應用程式。這個初始記憶體和最大記憶體在一定程度都會影響程式的效能。比如說在應用程式用到最大記憶體的時候,JVM是要先去做垃圾回收的動作,釋放被佔用的一些記憶體。
        所以想調整Tomcat的啟動時初始記憶體和最大記憶體就需要向JVM宣告,一般的JAVA程式在執行都可以通過中-Xms -Xmx來調整應用程式的初始記憶體和最大記憶體:

 如:java -Xms64m -Xmx128m a.jar.
tomcat的啟動程式是包裝過的,不能直接使用java -X..... tomcat.*來改變記憶體的設定。在Tomcat在改變這個設定
有兩種方法:
1.    就需要在環境變數中加上TOMCAT_OPTS, CATALINA_OPTS兩個屬性,
        如 SET CATALINA_OPTS= -Xms64m -Xmx512m;
        ms是最小的,mx是最大,64m, 512m分別是指記憶體的容量.
2.    修改Catalina.bat檔案
       在166行“rem Execute Java with the applicable properties ”以下每行
%_EXECJAVA% %JAVA_OPTS% %CATALINA_OPTS% %DEBUG_OPTS% -Djava.endorsed.dirs ="%JAVA_ENDORSED_DIRS%" -classpath "%CLASSPATH%" -Dcatalina.base="%CATALINA_BASE %" -Dcatalina.home="%CATALINA_HOME%" -Djava.io.tmpdir="%CATALINA_TMPDIR%" %MAINCLASS% %CMD_LINE_ARGS% %ACTION% 中的%CATALINA_OPTS% 替換成-Xms64m - Xmx512m

Tomcat效能優化

1.停用DNS查詢
server.xml裡
<Connector
port="8887" maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
debug="0" connectionTimeout="20000"
disableUploadTimeout="true" />

加上enableLookups="false";這樣就不使用DNS查詢,也不會有延遲了
除非需要所有連線到伺服器的HTTP客戶端的完整主機名稱

注:Connector的enableLookups性屬的意義是:呼叫request.getRemoteHost()是否會通過DNS查詢來取得遠處客戶端的真正主機名稱。true表示會查詢,false表示以字串格式傳回客戶端的IP地址。預設值是:true

2,調整執行緒的數目
Tomcat使用執行緒池以便對傳入的請求提供快速的響應。
通過更改Connector的minProcessors與maxProcessors的值,可以控制所分配的執行緒數目
將這兩個引數設為最佳值的最好方式是對各個引數嘗試許多不同的設定值,然後以模擬的網路流量進行測試,同時並觀察響應時間與記憶體的使用量。每一種機器、操 作系統與JVM的組合都可能有不同的表現,而且並非所有人的網站流量都會相同,所以沒有現成的規則來決定最小與最大的執行緒數

3.加快jsp的編譯速度,預先編譯jsp

4.容量規劃:經驗式的容量規劃,企業容量規劃

經驗式的容量規劃與企業容量規劃最大的差異就是深度。經驗式容量規劃使用經驗法則,因此比較像是經驗預測,而企業容量規劃則是深度地研究需求與效能,其目標是儘可能產生最精確的數字

實戰例子

pache+tomcat+mysql

            Apache+Tomcat+Mysql網站配置
前言:
公司開發了一個網站,估計最高線上人數是3萬,併發人數最多100人。開發的網站是否能否承受這個壓力,如何確保網站的負荷沒有問題,經過研究決定如下:
(1) 採用負載平衡和叢集技術,初步機構採用Apache+Tomcat的機群技術。
(2) 採用壓力測試工具,測試壓力。工具是Loadrunner。
硬體環境搭建:
為了能夠進行壓力測試,需要搭建一個環境。剛開始時,測試在公司區域網內進行,但很快發現了一個問題,即一個指令碼的壓力測試結果每次都不一樣,並且差別很大。原來是受公司網路的影響,於是決定搭建一個完全隔離的區域網測試。搭建後的區域網配置如下:
(1) 網路速度:100M
(2) 三臺伺服器:
負載伺服器 :作業系統windows2003,
Tomcat伺服器:作業系統windows2000 Professional
資料庫伺服器:作業系統windows2000 Professional
三臺機器的cpu 2.4 G, 記憶體 1G。
軟體環境搭建:
軟體的版本如下:
Apache 版本:2.054,
Tomcat5.0.30,
mysql :4.1.14.
JDK1.5
壓力測試工具:Loadrunner7.8。
負載平衡方案如下:
一臺機器(作業系統2003)安裝apache,作為負載伺服器,並安裝tomcat作為一個worker;一個單獨安裝tomcat,作為第二個worker;剩下的一臺單獨作為資料庫伺服器。
    Apache和tomcat的負載平衡採用JK1.2.14(沒有采用2.0,主要是2.0不再維護了)。
叢集方案:
     採用Tomcat本身的叢集方案。在server.xml配置。
壓力測試問題:
壓力測試後,發現了一些問題,現一一列出來:
(1)採用Tocmat集群后,速度變得很慢。因為集群后,要進行session複製,導致速度較慢。Tomcatd的複製,目前不支援 application 複製。複製的作用,主要用來容錯的,即一臺機器有故障後,apache可以把請求自動轉發到另外一個機器。在容錯和速度的考慮上,我們最終選擇速度,去掉 了Tomcat叢集。
(2) 作業系統最大併發使用者的限制:
為了採用網站的壓力,我們開始的時候,僅測試Tomcat的最大負載數。 Tomcat伺服器安裝的作業系統是windows2000 Professional。當我們用壓力測試工具,併發測試時,發現只要超過15個併發使用者,會經常出現無法連線伺服器的情況。經過研究,發現是作業系統 的問題:windows2000 Professional 支援的併發訪問使用者有限,預設的好像是15個。於是我們把作業系統全部採用windows2003 server版本。
(3) 資料庫連線池的問題:
測試資料庫連線效能時,發現數據庫連線速度很慢。每增加一些使用者,連線效能就差了很多。我們採用的資料庫連線池是DBCP,預設的初始化為50個,應該不 會很慢吧。查詢資料庫的連線數,發現初始化,只初始化一個連線。併發增加一個使用者時,程式就會重新建立一個連線,導致連線很慢。原因就在這裡了。如何解決 呢?偶爾在 JDK1.4下的Tomcat5.0.30下執行資料庫連線壓力測試,發現速度很快,程式建立資料庫連線的速度也是很快的。看來JDK1.5的JDBC驅 動程式有問題。於是我們修改 JDK的版本為1.4.

(4) C3P0和DBCP
C3P0是Hibernate3.0預設的自帶資料庫連線池,DBCP是Apache開發的資料庫連線池。我們對這兩種連線池進行壓力測試對比,發現在併發300個使用者以下時,DBCP比C3P0平均時間快1秒左右。但在併發400個使用者時,兩者差不多。

速度上雖然DBCP比C3P0快些,但是有BUG:當DBCP建立的資料庫連線,因為某種原因斷掉後,DBCP將不會再重新建立新的連線,導致必須重新啟動Tomcat才能解決問題。DBCP的BUG使我們決定採用C3P0作為資料庫連線池。
調整後的方案:
作業系統Windows2003 server版本
JDK1.4
Tomcat 5.0.30
資料庫連線池C3P0
僅採用負載平衡,不採用叢集。
軟體的配置:
Apache配置:主要配置httpd.conf和新增加的檔案workers.properties
Httpd.conf:
#一個連線的最大請求數量
MaxKeepAliveRequests 10000 
#NT環境,只能配置這個引數來提供效能
<IfModule mpm_winnt.c> 
#每個程序的執行緒數,最大1920。NT只啟動父子兩個程序,不能設定啟動多個程序
ThreadsPerChild 1900
每個子程序能夠處理的最大請求數
MaxRequestsPerChild 10000
</IfModule>

# 載入mod_jk
#
LoadModule jk_module modules/mod_jk.so
#
# 配置mod_jk
#
JkWorkersFile conf/workers.properties
JkLogFile logs/mod_jk.log
JkLogLevel info
#請求分發,對jsp檔案,.do等動態請求交由tomcat處理
DocumentRoot "C:/Apache/htdocs"
JkMount /*.jsp loadbalancer
JkMount /*.do loadbalancer
JkMount /servlet/* loadbalancer
#關掉主機Lookup,如果為on,很影響效能,可以有10多秒鐘的延遲。
HostnameLookups Off
#快取配置
LoadModule cache_module modules/mod_cache.so
LoadModule disk_cache_module modules/mod_disk_cache.so
LoadModule mem_cache_module modules/mod_mem_cache.so

<IfModule mod_cache.c>
CacheForceCompletion 100
CacheDefaultExpire 3600
CacheMaxExpire 86400
CacheLastModifiedFactor 0.1

<IfModule mod_disk_cache.c>
CacheEnable disk /
CacheRoot c:/cacheroot
CacheSize 327680
CacheDirLength 4
CacheDirLevels 5
CacheGcInterval 4
</IfModule>
<IfModule mod_mem_cache.c>
CacheEnable mem /
MCacheSize 8192
MCacheMaxObjectCount 10000
MCacheMinObjectSize 1
MCacheMaxObjectSize 51200
</IfModule>
</IfModule>
worker. Properties檔案
#
# workers.properties ,可以參考
::URL::http://jakarta.apache.org/tomcat/connectors-doc/config/workers.html
# In Unix, we use forward slashes:
ps=/

# list the workers by name

worker.list=tomcat1, tomcat2, loadbalancer

# ------------------------
# First tomcat server
# ------------------------
worker.tomcat1.port=8009
worker.tomcat1.host=localhost
worker.tomcat1.type=ajp13

# Specify the size of the open connection cache.
#worker.tomcat1.cachesize

#
# Specifies the load balance factor when used with
# a load balancing worker.
# Note:
# ----> lbfactor must be > 0
# ----> Low lbfactor means less work done by the worker.
worker.tomcat1.lbfactor=900

# ------------------------
# Second tomcat server
# ------------------------
worker.tomcat1.port=8009
worker.tomcat1.host=202.88.8.101
worker.tomcat1.type=ajp13

# Specify the size of the open connection cache.
#worker.tomcat1.cachesize

#
# Specifies the load balance factor when used with
# a load balancing worker.
# Note:
# ----> lbfactor must be > 0
# ----> Low lbfactor means less work done by the worker.
worker.tomcat1.lbfactor=2000

# ------------------------
# Load Balancer worker
# ------------------------

#
# The loadbalancer (type lb) worker performs weighted round-robin
# load balancing with sticky sessions.
# Note:
# ----> If a worker dies, the load balancer will check its state
#        once in a while. Until then all work is redirected to peer
#        worker.
worker.loadbalancer.type=lb
worker.loadbalancer.balanced_workers=tomcat1,tomcat2

#
# END workers.properties
#

Tomcat1配置:
<!--配置server.xml
去掉8080埠,即註釋掉如下程式碼:-->
<Connector 
port="8080" maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
               enableLookups="false" redirectPort="8443" acceptCount="100"
               debug="0" connectionTimeout="20000" 
               disableUploadTimeout="true" />

<!--配置8009埠如下:-->
<Connector port="8009" 
maxThreads="500" minSpareThreads="400" maxSpareThreads="450"
               enableLookups="false" redirectPort="8443" debug="0"
               protocol="AJP/1.3" />
<!--配置引擎--> 
<Engine name="Catalina" defaultHost="localhost" debug="0" jvmRoute="tomcat1">

啟動記憶體配置,開發configure tomcat程式即可配置:
Initial memory pool: 200 M
Maxinum memory pool:300M
Tomcat2配置:
配置和tomcat1差不多,需要改動的地方如下:
<!--配置引擎--> 
<Engine name="Catalina" defaultHost="localhost" debug="0" jvmRoute="tomcat2">

啟動記憶體配置,開發configure tomcat程式即可配置:
Initial memory pool: 512 M
Maxinum memory pool:768M
Mysql配置:
Server型別:Dedicated MySQL Server Machine 
Database usage:Transational Database Only
併發連線數量:Online Transaction Processing(OLTP)
字符集:UTF8
資料庫連線池的配置:
我們採用的是spring 框架,配置如下:
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.connection.driver_class">com.mysql.jdbc.Driver</prop>
<prop key="hibernate.connection.url">jdbc:mysql://202.88.1.103/db</prop>
<prop key="hibernate.connection.username">sa</prop>
<prop key="hibernate.connection.password"></prop>

<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.use_sql_comments">false</prop>

<prop key="hibernate.cglib.use_reflection_optimizer">true</prop>
<prop key="hibernate.max_fetch_depth">2</prop>

<prop key="hibernate.c3p0.max_size">200</prop>
<prop key="hibernate.c3p0.min_size">5</prop>
<prop key="hibernate.c3p0.timeout">12000</prop>
<prop key="hibernate.c3p0.max_statements">50</prop>
<prop key="hibernate.c3p0.acquire_increment">1</prop>
</props>
</property>
其他的沒有額外配置。
LoadRunner 常見問題:
(1)sofeware caused connction:這種情況,一般是指令碼有問題,或者loadrunner有問題。解決方法:重新啟動機器,或者重新錄製指令碼,估計是loadrunner的bug。
(2)cannot connect to server:無法連線到伺服器。這種情況是伺服器的配置有問題,伺服器無法承受過多的併發連線了。需要優化伺服器的配置,
如作業系統採用windows 2003 server,
優化tomcat配置:maxThreads="500" minSpareThreads="400" maxSpareThreads="450"。但是tomcat 最多支援500個併發訪問
優化apache配置:
ThreadsPerChild 1900
MaxRequestsPerChild 10000
其他的錯誤如:
Action.c(10): Error -27791: Server has shut down the connection prematurely
HTTP Status-Code=503 (Service Temporarily Unavailable)
一般都是由於伺服器配置不夠好引起的,按照問題(2)處理,如果仍舊不行,需要優化硬體和調整程式了。
Apache問題:
(1) File does not exist: C:/Apache/htdocs/favicon.ico:
這個問題是apache,htdocs目錄沒有favicon.ico檔案引起的,該檔案是網站的圖示,僅在firefox,myIE等瀏覽器出現。
(2) 圖片無法顯示:
配置apache後,卻無法顯示圖片。
解決方法:把程式的圖片,按照程式結構copy到apache的htdocs目錄下。
(3) 無法處理請求:
當我們輸入 ***.do 命令後,apache確返回錯誤資訊,而連線tomcat卻沒有問題。原因是沒有把.do命令轉發給tomcat處理。解決方法如下:
在apache配置檔案中配置如下內容:
DocumentRoot "C:/Apache/htdocs"
JkMount /*.jsp loadbalancer
JkMount /*.do loadbalancer


總結:
網站的壓力測試,涉及的知識面挺廣的,不僅要熟悉壓力測試工具,還要知道如何配置和優化應用伺服器和資料庫,並且需要知道如何優化網路、作業系統、硬體系統。
測試中不僅要善於發現問題,要知道如何解決。最重要的一點,要有良好的測試方法。剛開始測試時,可以從最簡單的測試指令碼入手,不需要太複雜的指令碼,這樣便 於發現問題。如我們剛開始時,就從一個簡單的下載登陸介面的指令碼入手,測試一個tomcat的壓力負載。一個簡單的獲取登陸的指令碼,幫助我們優化了 tomcat的配置;後來再測試資料庫連線,也是一個簡單的資料庫連線指令碼,幫助我們優化了資料庫連線池;然後利用這些簡單的指令碼,測試apache的負 載平衡,優化了apache配置。最後運行復雜的指令碼,模擬多種角色的使用者在不同時間下的處理,以測試網站壓力負載。