負載平衡方案如下:
一臺機器(操作系統(tǒng)2003)安裝apache,作為負載服務器,并安裝tomcat作為一個worker;一個單獨安裝tomcat,作為第二個worker;剩下的一臺單獨作為數據庫服務器。
Apache和tomcat的負載平衡采用JK1.2.14(沒有采用2.0,主要是2.0不再維護了)。
集群方案:
采用Tomcat本身的集群方案。在server.xml配置。
壓力測試問題:
壓力測試后,發(fā)現了一些問題,現一一列出來:
(1) 采用Tocmat集群后,速度變得很慢。因為集群后,要進行session復制,導致速度較慢。Tomcatd的復制,目前不支持application復制。復制的作用,主要用來容錯的,即一臺機器有故障后,apache可以把請求自動轉發(fā)到另外一個機器。在容錯和速度的考慮上,我們最終選擇速度,去掉了Tomcat集群。
(2) 操作系統(tǒng)最大并發(fā)用戶的限制:
為了采用網站的壓力,我們開始的時候,僅測試Tomcat的最大負載數。Tomcat服務器安裝的操作系統(tǒng)是windows2000 Professional。當我們用壓力測試工具,并發(fā)測試時,發(fā)現只要超過15個并發(fā)用戶,會經常出現無法連接服務器的情況。經過研究,發(fā)現是操作系統(tǒng)的問題:windows2000 Professional 支持的并發(fā)訪問用戶有限,默認的好像是15個。于是我們把操作系統(tǒng)全部采用windows2003 server版本。
(3) 數據庫連接池的問題:
測試數據庫連接性能時,發(fā)現數據庫連接速度很慢。每增加一些用戶,連接性能就差了很多。我們采用的數據庫連接池是DBCP,默認的初始化為50個,應該不會很慢吧。查詢數據庫的連接數,發(fā)現初始化,只初始化一個連接。并發(fā)增加一個用戶時,程序就會重新創(chuàng)建一個連接,導致連接很慢。原因就在這里了。如何解決呢?偶爾在JDK1.4下的Tomcat5.0.30下執(zhí)行數據庫連接壓力測試,發(fā)現速度很快,程序創(chuàng)建數據庫連接的速度也是很快的。看來JDK1.5的JDBC驅動程序有問題。于是我們修改 JDK的版本為1.4.
(4) C3P0和DBCP
C3P0是Hibernate3.0默認的自帶數據庫連接池,DBCP是Apache開發(fā)的數據庫連接池。我們對這兩種連接池進行壓力測試對比,發(fā)現在并發(fā)300個用戶以下時,DBCP比C3P0平均時間快1秒左右。但在并發(fā)400個用戶時,兩者差不多。
速度上雖然DBCP比C3P0快些,但是有BUG:當DBCP建立的數據庫連接,因為某種原因斷掉后,DBCP將不會再重新創(chuàng)建新的連接,導致必須重新啟動Tomcat才能解決問題。DBCP的BUG使我們決定采用C3P0作為數據庫連接池。
調整后的方案:
操作系統(tǒng)Windows2003 server版本
JDK1.4
Tomcat 5.0.30
數據庫連接池C3P0
僅采用負載平衡,不采用集群。
軟件的配置:
Apache配置:主要配置httpd.conf和新增加的文件workers.properties
Httpd.conf:
#一個連接的最大請求數量
MaxKeepAliveRequests 10000
#NT環(huán)境,只能配置這個參數來提供性能
<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
#請求分發(fā),對jsp文件,.do等動態(tài)請求交由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 ,可以參考
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">
啟動內存配置,開發(fā)configure tomcat程序即可配置:
Initial memory pool: 200 M
Maxinum memory pool:300M
Tomcat2配置:
配置和tomcat1差不多,需要改動的地方如下:
<!--配置引擎-->
<Engine name="Catalina" defaultHost="localhost" debug="0" jvmRoute="tomcat2">
啟動內存配置,開發(fā)configure tomcat程序即可配置:
Initial memory pool: 512 M
Maxinum memory pool:768M
Mysql配置:
Server類型:Dedicated MySQL Server Machine
Database usage:Transational Database Only
并發(fā)連接數量: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:無法連接到服務器。這種情況是服務器的配置有問題,服務器無法承受過多的并發(fā)連接了。需要優(yōu)化服務器的配置,
如操作系統(tǒng)采用windows 2003 server,
優(yōu)化tomcat配置:maxThreads="500" minSpareThreads="400" maxSpareThreads="450"。但是tomcat 最多支持500個并發(fā)訪問
優(yōu)化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)處理,如果仍舊不行,需要優(yōu)化硬件和調整程序了。
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命令轉發(fā)給tomcat處理。解決方法如下:
在apache配置文件中配置如下內容:
DocumentRoot "C:/Apache/htdocs"
JkMount /*.jsp loadbalancer
JkMount /*.do loadbalancer
總結:
網站的壓力測試,涉及的知識面挺廣的,不僅要熟悉壓力測試工具,還要知道如何配置和優(yōu)化應用服務器和數據庫,并且需要知道如何優(yōu)化網絡、操作系統(tǒng)、硬件系統(tǒng)。
測試中不僅要善于發(fā)現問題,要知道如何解決。最重要的一點,要有良好的測試方法。剛開始測試時,可以從最簡單的測試腳本入手,不需要太復雜的腳本,這樣便于發(fā)現問題。如我們剛開始時,就從一個簡單的下載登陸界面的腳本入手,測試一個tomcat的壓力負載。一個簡單的獲取登陸的腳本,幫助我們優(yōu)化了tomcat的配置;后來再測試數據庫連接,也是一個簡單的數據庫連接腳本,幫助我們優(yōu)化了數據庫連接池;然后利用這些簡單的腳本,測試apache的負載平衡,優(yōu)化了apache配置。最后運行復雜的腳本,模擬多種角色的用戶在不同時間下的處理,以測試網站壓力負載。
DBCP使用apache的對象池ObjectPool作為連接池的實現,在構造GenericObjectPool時,會生成一個內嵌類Evictor,實現自Runnable接口。如果_timeBetweenEvictionRunsMillis大于0,每過_timeBetweenEvictionRunsMillis毫秒Evictor會調用evict()方法,檢查對象的閑置時間是否大于 _minEvictableIdleTimeMillis毫秒(_minEvictableIdleTimeMillis小于等于0時則忽略,默認為30分鐘),是則銷毀此對象,否則就激活并校驗對象,然后調用ensureMinIdle方法檢查確保池中對象個數不小于_minIdle。在調用returnObject方法把對象放回對象池,首先檢查該對象是否有效,然后調用PoolableObjectFactory 的passivateObject方法使對象處于非活動狀態(tài)。再檢查對象池中對象個數是否小于_maxIdle,是則可以把此對象放回對象池,否則銷毀此對象
還有幾個很重要的屬性,_testOnBorrow、_testOnReturn、_testWhileIdle,這些屬性的意義是取得、返回對象和空閑時是否進行驗證,檢查對象是否有效,默認都為false即不驗證。所以當使用DBCP時,數據庫連接因為某種原因斷掉后,再從連接池中取得連接又不進行驗證,這時取得的連接實際已經時無效的數據庫連接了。網上很多說DBCP的bug應該都是如此吧,只有把這些屬性設為true,再提供_validationQuery語句就可以保證數據庫連接始終有效了,oracle數據庫可以使用SELECT COUNT(*) FROM DUAL,不過DBCP要求_validationQuery語句查詢的記錄集必須不為空,可能這也可以算一個小小的BUG,其實只要_validationQuery語句執(zhí)行通過就可以了。
聯系客服