Web下的性能測試與優化

        隨着Internet的日益普及,現在基於B/S結構的大型應用越來越多,可如何對這些應用進行測試成爲日益迫切的問題。
        B/S下的功能測試比較簡單,關鍵是如何做好性能測試。 目前大多數的測試人員認爲只要跑一些測試工具證明我的產品是可以達到性能的就ok了,爲了證明而去測試是沒有任何價值的,關鍵是要發現產品性能上的缺陷,定位問題,解決問題,這纔是測試要做的。
        首先我們從兩個方面分析如何進行WEB測試,從技術實現上來講一般的B/S結構,無論是.NET還是J2EE,都是多層構架,有界面層,業務邏輯層,數據層。而從測試的流程上來說,首先是發現問題,分析問題,定位問題,再由開發人員解決問題。那麼B/S的結構的測試如何來做?
        如何發現問題是首先要介紹的,在做WEB測試之前你需要一些資料,比如產品功能說明書,性能需求說明書,不一定很完善,但一定要有,明確測試目標,這是基本的常識,可是我們往往看到的是已經開始動手測了,但還不知自己的系統要達到的性能指標是什麼。這裏先簡單講一下測試的性能指標:
        通用指標(指Web應用服務器、數據庫服務器必需測試項):
  * ProcessorTime: 指服務器CPU佔用率,一般平均達到70%時,服務就接近飽和;
  * Memory Available Mbyte :   可用內存數,如果測試時發現內存有變化情況也要注意,如果是內存泄露則比較嚴重;
  * Physicsdisk Time  : 物理磁盤讀寫時間情況;
        Web服務器指標:
  * Avg Rps: 平均每秒鐘響應次數= 總請求時間 / 秒數;
  * Avg time to last byte per terstion (mstes):平均每秒業務角本的迭代次數 ,有人會把這兩者混淆;
  * Successful Rounds:成功的請求;
  * Failed  Rounds :失敗的請求;
  * Successful  Hits :成功的點擊次數;
  * Failed  Hits :失敗的點擊次數;
  * Hits Per Second :每秒點擊次數;
  * Successful  Hits Per Second :每秒成功的點擊次數;
  * Failed  Hits Per Second :每秒失敗的點擊次數;
  * Attempted  Connections :嘗試鏈接數;
        數據庫服務器指標:
  * User 0  Connections :用戶連接數,也就是數據庫的連接數量;
  * Number of deadlocks:數據庫死鎖;
  * Butter Cache hit :數據庫Cache的命中情況; 
       上面的指標只是一些常用的指標,對於不同的應用你還必需作相應的調整,比如程序使用的是.NET技術的,則必需加入一些針對性的測試指標。對於這些指標的詳細瞭解,你可以參考Windows下面的 SystemMonitor的幫助與LoadRunner、ACT的幫助。對於發現問題,指標的設置非常重要,它會幫你定性的發現一些錯誤。
       對於定性的壓力測試就不做過多的分析了,工具很多,流行的主要有LoadRunner,ACT,WAS,WebLoad,各個工具有它的使用範圍,其中我個人認爲LoadRunner 最全面,它提供了多種協議的支持,對複雜的壓力測試都可以勝任,WAS與ACT則對微軟的技術支持的比較好,其中WAS支持分佈式機羣測試,ACT則是與.NET集成比較好,支持ViewState (.NET 下控件緩存的支持) 的測試。
       在這一階段測試你要不斷的跟據系統的測試目標進行變化,一開始由於系統過於龐大,所以我們要分成若干個子系統,各個子系統的性能目標必需明確,主要是給併發的指標定一個閥值,同時設定一些與系統相關的測試參數,應用服務器,數據庫服務器都要有,對達不到閥值的與一些通用參數有問題的子系統進行深入分析。比如它的併發達不到你的要求,證明子系統性能有問題,或是數據庫用戶連接過高,程序沒有釋放用戶連接等等。
       然後我們要對子系統進行詳細測試,由於B/S 結構下,圖片的請求對性能的影響較大,所以我們對子系統測試時要分兩個部分進行:
       一、非程序部分,即圖片、讀取的文件等等;
       二、應用程序本身。
       通過事務或函數的分離,可以把這兩塊實現單獨的測試,具體做法可以參考各個工具的手冊。
       對子系統的測試參數的設置要求則更高,它有助你後面精確的定位問題,比如對異常,死鎖,網絡流量等等前面沒有注意到的情況的增加,同時你要注意增加測試參數的收集對系統的性能影響比較大,所以一般不要超過10個,剛剛介紹的整體的性能測試指標也不要增加很多,這樣影響會小一點。
       最後在這一階段要說明的是數據庫的數據量會很大程度的影響性能,所以要根據前面的性能需求說明書向數據庫中模擬相應的數據量,來進行測試,這樣纔有更高的可信度。
       
       上面所說的是對問題的發現,下面就是分析問題原因,這一步的要求比較高,一般由測試人員與程序員配合完成,當然如果你有相當的開發經驗,再做這方面的測試,就更爲難得。下面我們說說如何精確定位問題,出現問題的可能性可能有很多種,大致分以下幾種:
       一、性能達不到目標;
       二、性能達到目標,但有一些其它的問題,比如異常,死鎖,緩存命中過低,網絡流量較大;
       三、服務器穩定性的問題,比如內存泄漏……。
       要發現這些問題起馬的要求要有一款使用的比較稱心的性能分析與優化工具,比如微軟的.NET下就有自己開發的工具,對Borland的Java開發工具中也有類似的工具,但我個人認爲更好的工具是Rose下的Purify與Quantify,主要是他對.net 與java ,C++都有支持,而且分析效果特別專業。
       我們先了解一下Rational Purify,  Rational Purify 能自動找出Visual C/C++ 和Java 代碼中與內存有關的錯誤,確保整個應用程序的質量和可靠性。在查找典型的Visual C/C++ 程序中的傳統內存訪問錯誤,以及Java,C# 代碼中與垃圾內存收集相關的錯誤方面;Rational Quantity 則是一款針對函數級的性能分析利器,使用它你可以從圖形化的界面中得到函數調用的時間,百分比與次數,以及子函數所佔時間,使你可以更快的定位性能瓶頸。
       我們再來說說性能優化與異常的處理,性能優化有一個原則,即用時間比例最大的進行優化,效果才最明顯,比如有個函數它的執行時間爲30秒,如果你優化了一百倍則執行時間爲0.3秒,提升了29.7秒,而如果它的執行時間爲0.3秒,優化後爲0.003秒,實際提升了0.297秒,提升的效果並不明顯,而且寫過程序的人都知道,後者性能優化的代價更大。
       在性能優化的過程中,一般是先數據庫,後程序,因爲數據庫的優化不需要修改程序,修改的風險很小。但如何才能確定是數據庫的問題,這就需要技巧,在使用Quantity時,你一路分析下去,大多數最終會發現,是數據庫查詢函數佔用時間比較大, 比如什麼,SqlCmd.ExecuteNoQuery等等數據庫執行函數,這時你就需要分析數據庫。
       數據庫的分析原則是先索引,後存儲過程,最後表結構視圖的優化,索引的優化是最簡單也是通常最有效的方法,如果合理的使用會帶來意想不到不到的效果。在這裏要給大家簡單的介紹一下SQLProfile,SQL查詢分析器,SQLProfile是一個SQL語句跟蹤器,可以跟蹤程序流程使用的SQL語句與存儲過程,結合查詢分析器對SQL的分析,可以對索引的優化做出很好的判斷,但索引也不是萬能的,在增刪改較多的表,索引過多會引起這些操作的性能下降,所以判斷還是需要一定的經驗。 同時針對用戶使用頻度最高的SQL進行優化也是最行之有效的,這時則需要Precise,它可以觀測某一個較長時間內的SQL語句的執行情況。數據庫優化的潛能挖光後,如果還是達不到性能要求或是還有問題,則要從程序來進行優化,這是程序員做的事,測試人員要做的,就是告訴他們,哪個函數執行過多引起了性能下降,比如異常過多,某個循環過多,或是DCOM調用過多等等,但說服程序員也是一件不容易的事,你要在這一階段做的出色一定要有幾年的編程經驗,並且要讓程序員感到聽你的性能會有提升,這是一件很不容易的事情哦。
       內存的分析,一般是一個長期分析的過程,要做好不容易,首先要有長期奮戰的準備,其次內存泄漏的分析最好是放在單元測試之中同步進行,而不是要等到最後再去發現問題,當然出了問題也只好面對,一般這類問題都是在服務器運行了很久才暴露出來,一旦發現問題後,則需要定位問題,分析的原則採用子系統相互獨立運行,找到最小問題的系統集,或是藉助內存分析工具觀察內存對象情況,初步定位問題,再用Purify進行運行時分析,通常C++ 內存問題比較多,Java與.NET比較少,一般由GC不合理引起。C++的內存錯誤就比較多了,主要常見的有:

:       1、Array Bounds Read (ABR) :數組越界讀
       2、Array Bounds Write (ABW):數組越界寫
       3、Beyond stack Read (BSR):堆棧越界讀
       4、Free Memory Read(FMR):空閒內存讀
       5、Invalid pointer Read(IPR):非法指針閱讀
        6、Null Pointer Read(NPR):  空指針閱讀
        7、Uninitialized Memory Read(UMR):未初始化內存讀寫
        8、Memory Leak:內存泄漏
        (注:如果需要更多的信息,可以參見Purify的幫助信息)
        順便提一句,爲什麼要說單元測試時做這個比較好,由於單元測試針對的是單一功能,這時結合單元測試案例做內存分析會更快的定位問題,同時由於問題較早的發現,則後期的風險則會減少,當然如果結合代碼覆蓋工具PureCoverage 來做就更完美了。
       
附:分析數據庫死鎖原因的方法
        常看到死鎖的問題,一般都是KILL進程,但如果不查出引起死鎖的原因,死鎖會時常發生。
        可以通過查找引起死鎖的的操作,就可以方便的解決死鎖。

        1、死鎖發生時,通過如下語法,查詢出引起死鎖的操作

 use master
 go
 declare @spid int,@bl int
 DECLARE s_cur CURSOR FOR
 select  0 ,blocked
 from (select * from sysprocesses where  blocked>0 ) a
 where not exists(select * from (select * from sysprocesses where  blocked>0 ) b
 where a.blocked=spid)
 union select spid,blocked from sysprocesses where  blocked>0
 OPEN s_cur
 FETCH NEXT FROM s_cur INTO @spid,@bl
 WHILE @@FETCH_STATUS = 0
 begin
 if @spid =0
            select '引起數據庫死鎖的是: '+ CAST(@bl AS VARCHAR(10)) + '進程號,其執行的SQL語法如下'
 else
            select '進程號SPID:'+ CAST(@spid AS VARCHAR(10))+ '被' + '進程號SPID:'+ CAST(@bl AS VARCHAR(10)) +'阻塞,其當前

進程執行的SQL語法如下'
 DBCC INPUTBUFFER (@bl )
 FETCH NEXT FROM s_cur INTO @spid,@bl
 end
 CLOSE s_cur
 DEALLOCATE s_cur

 exec sp_who2
 
        2、查找程序/數據庫
 
        3、分析找到的,並解決問題

 

發佈了59 篇原創文章 · 獲贊 16 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章