外部環境調整
調整非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.容量規劃:經驗式的容量規劃,企業容量規劃
經驗式的容量規劃與企業容量規劃最大的差異就是深度。經驗式容量規劃使用經驗法則,因此比較像是經驗預測,而企業容量規劃則是深度地研究需求與性能,其目標是盡可能產生最精確的數字
apache+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配置。最後運行復雜的腳本,模擬多種角色的用戶在不同時間下的處理,以測試網站壓力負載。