性能測試新手誤區

性能測試新手誤區(一):找不到測試點,不知爲何而測

發佈時間: 2012-4-17 10:19    作者: msnshow    來源: 51Testing軟件測試博客 

 

  有過一些性能測試經驗的人很容易進入此狀態,他們已經熟悉了性能測試的基本流程,能夠比較熟練的使用測試工具開展工作。我大概從事性能測試一年左右時遇到了這個問題,那時我覺得性能測試的過程沒有太多挑戰,遇到的每一個系統,彷彿都可以用同樣的流程完成。半天時間填寫測試方案,一天時間來準備測試環境,一天時間準備測試腳本,一到兩天來完成各種測試用例(基準測試、日常壓力測試、峯值壓力測試、絕對併發測試、穩定性測試等),然後就是調優、問題複測和完成測試報告。在我看來,性能測試好像變成了用一些工具去執行一個個固定的用例。

 

  這樣的工作持續了一段時間後,我感到有些不對勁,一定是哪裏出了問題。性能測試難道真的這麼簡單,簡單到把任何一個系統套入標準的流程中就可以了?於是我開始思考測試的意義,爲什麼要進行性能測試?是因爲性能測試可以提供關於瓶頸、缺陷、效率等等我們認爲有價值的信息。那僅僅通過一個工具,或者是一個固定的流程,就可以發現不同系統的這些信息麼?這顯然是不可能的。

 

  我開始嘗試儘量深入的去理解被測系統,這個系統的目的是什麼,用戶是如何使用系統的,用戶對哪些業務的性能比較敏感,系統的一些關鍵業務實現邏輯是怎麼樣的,從設計實現的角度來看哪些業務的性能可能存在隱患。這些很少是技術層面上的問題,需要做的只是思考,再深入思考。慢慢的我有了些收穫,開始瞭解爲什麼要測這個系統,針對這個特定的系統哪些內容是最重要的,爲了獲得需要的信息我需要從哪幾個方面進行測試,爲了實現我的想法又需要哪幾種方法或者工具。(現在我的性能測試過程中,用於理解被測系統、理解用戶、整理測試思路的時間投入大大增加了。你呢,投入了多大比例?)

 

  要做好這些其實很難,每一個被測系統對我來說,彷彿就變成了一個新的挑戰。但是逐漸的我發現自己思考問題更全面了、可以更快的抓住系統的重點、找到更重要的BUG、對系統的實際性能有了更準確的評估。這裏提一個簡單的問題,如何確保你的測試結果和生產環境的性能表現是一致的,也就是說測試結果能夠真正的反應實際的性能,而不僅僅是代表了你選取的幾個測試場景的性能。話說起來比較繞,但是請認真想一想,你有多大的把握呢?

 

  上面只是寫了一些個人的感想,我覺得如果在“思想”上沒有辦法上到一個新的臺階,你的性能測試生涯可能也就達到“瓶頸”了。如何突破這個瓶頸,那就需要努力改變自身,多思考多學習,最核心的能力恐怕不是能培訓出來的。一定會有一些人認爲性能測試的重點在於“技術”上,於是他們不斷的記住各種調優配置參數,以爲自己掌握了性能的精髓,彷彿什麼系統到了他們手上,只要改幾個參數就會出現奇蹟。我也經歷了這個階段,也有過幾次自以爲挺高明的調優經歷,也爲自己會各種中間件數據庫的配置調優而有些小得意。但現在想想,那還真是一個比較低的層次,思想上抓不住重點、看不全大局,技術上其實也只是一點皮毛。面對這類人,只要問幾個爲什麼就會讓他們無法回答,爲什麼要調優?爲什麼要調這個參數?如何證明這次調整的效果?

 

  將上文簡單的總結成幾點,希望能給性能測試新手提供一丁點的幫助吧:

 

  1、性能測試的難點在於對被測系統的理解,在於對測試點的分析。爲了實現測試的思想,可以有多種方法,手段永遠只是輔助的,只有思想纔是根本的。工具(如LR)更不等於性能測試,不要以爲會用LR就懂了性能測試,那只是最低級的測試執行。也不要以爲會調幾個參數就懂了性能測試,那同樣是個比較低的層次。

 

  2、調優等技術不是性能測試的主要目的,好的性能也不是調出來的。測試人員一定要明白自己存在的價值所在,所謂的“技術”只是爲了達成自己測試目的的一些手段,同開發人員、DBA相比,你在這些技術上永遠是外行。

 

  3、不要照着文檔模板,填入測試方案。每一個系統都是不同的,要真正的認識到這一點,爲每個系統設計出有針對性的測試方案。思考你每一步工作的意義和目的。

 

  4、如何證明測試結果的有效性,其實是個很難的問題,值得花費時間去認真思考。這個過程涉及到一些很重要的內容,如用戶模型的建立,後續會有專門的文章。

 

5、性能測試是一個需要不斷改進的過程,每一次只需儘量的做到更好,多做一點點以前沒有想到的東西。經過不斷的積累,你會發現自己對性能測試有了更深的認識。

 

性能測試新手誤區(二):爲什麼我模擬的百萬測試數據是無效的?

  測試環境的重要性無需多說,大家都知道測試環境要儘量的模擬生產環境,當然也包括數據。這樣測試的結果纔會更加準確的反應真實的性能。就連開發過程,都已經開始在大數據量下加壓開發了。那麼,關於測試數據,你瞭解多少呢?

  通常說的測試數據可以分爲兩類:

  一是爲了測試性能而準備的數據,這是用來模擬“壓力”的數據。也就是常說的數據量、歷史數據等。一般都會根據需求或者經驗很容易估算出來,比如案件年增長量爲5%,去年數據量爲100W,測試需要保證3年後系統仍可正常運行,那麼就需要計算並模擬出3年後的總數據量,在這個基礎上進行測試。

  二是用來輔助測試使用的數據。比如有一個對案件進行打分的功能,只有符合一定條件的案件纔會出現在打分列表中。那麼我們要測這個打分的操作,首先就要保證有可用的案件,這就需要去生成測試數據,該數據可能一經使用就失效了(已經打過分就不能再打了)。這樣,每次測試這個功能,就需要準備這樣一批數據。這裏的測試數據,更多的是和測試流程有關,是爲了能夠正常的進行測試,而不是涉及到性能的。

  我們這裏要說的是第一類,對性能測試結果產生直接影響的數據。

  先看兩個小案例,涉及到了案件表(T_AJ)和法院編號列(N_FY)、立案日期列(D_LARQ)。案件表中模擬了一百萬測試數據,測試簡單的查詢操作,根據經驗,預期響應時間在2秒之內。

  案例1.查詢本院案件列表,相應的SQL如下:

select * from T_AJ

where N_FY=10

order by D_LARQ desc

 執行這個操作耗時近10s,顯然達不到正常預期。

  經排查,生成的100W測試數據中,所有的N_FY列值都爲10。這樣,最明顯的問題就是,查詢的結果集數量完全偏離了正常範圍。如果實際有100家法院,正常分佈下,每家法院只有1W的案件,但測試數據的FY只有一個值,通過這個查詢,查出了原來100家法院的數據。無論是在數據庫處理中(如本例的排序),還是在程序的處理中(如展現或者是對數據做進一步處理),兩者的性能差異都是很顯著的。所以這個測試結果是無效的。

  有人說,這個例子太弱了,結果集差了100倍,性能當然不一樣了。那是不是數據總量和結果集大小都一致,測試結果就是有效了呢?

  案例2.查詢本院一個月內收的案件,相應SQL如下:

select * from T_AJ

where N_FY=10 and D_LARQ between '20110101' and '20110201'


 這個操作,查出來的結果只有一千條數據,屬於正常範圍。但查詢的時間還是超過5秒,依然超出了我們的預期。

 

  查看數據發現,N_FY=10的數據有近50萬,佔了總數據量的一半,D_LARQ在一月份的數據也佔了差不多一半。但是同時符合兩個條件的數據還是一千條左右。那麼這裏的問題就不在於結果集了,而是是否能利用索引進行查詢,看如下兩個圖就能很好理解了。

 

  在正常數據中,每家法院的數據可能佔總數據量的1%,一個月時間段內的數據可能佔總數據量更少,假設是0.5%。那麼這時我們通過N_FY和D_LARQ兩個條件進行查詢,數據庫會進行估算:符合D_LARQ查詢條件的數據大概有5000條,符合N_FY查詢條件的數據大概有1萬條,那麼用D_LARQ上的索引進行查詢是最快的,可以迅速的將查詢範圍縮小到5000條,然後在這5000條中去檢查N_FY是否也符合條件。

 

過程如圖一所示(手繪草圖^_^)。


注:數據按行存儲,小方塊表示符合該列查詢條件的數據,陰影表示符合所有查詢條件,也就是最終的結果集。箭頭線段表示爲了完成查詢,需要掃描的數據量,本圖中即符合LARQ查詢條件的數據。下同。

 但在本例中不正常的數據條件下,數據庫會知道:符合N_FY查詢條件的數據有50萬條,符合D_LARQ的也有近50萬條,如果使用其中一列的索引將一百萬的範圍縮減到50萬,比從頭到尾掃描整個表做的工作還要多(爲什麼呢?需要了解索引的結構和原理),那還是不要用索引了吧。於是數據庫會依次檢查每一條數據,判斷N_FY和D_LARQ是否符合條件。

 

  如圖二所示。


  注:本圖中實際掃描的數據量就是整張表的數據,但結果集和圖一是一樣大的。

  這樣,就可以知道,總數據量一樣,結果集大小一樣,爲什麼性能差了很多了。就是因爲數據分佈不合理,導致數據庫無法正常使用索引,從而進行了全表掃描。當然,這個數據分佈,我們依然可以歸類到結果集中去,那就是要保證每一個查詢條件“單獨的結果集”都要符合真實情況,而不僅僅是整個查詢最終的“總結果集”。

  看個這兩個簡單的小例子,我們再來總結一下關於測試數據,需要注意的內容:

  1、最根本、也是大家都知道的就是數據量,性能測試必須保證能在預期的數據量下進行測試。在一萬條記錄中查詢,和在一百萬數據中查詢,顯然是大大不同的,可以把數據量看做一種“壓力”,這個就不用再解釋了。

  但是在比較大型的系統中,這一點可能也不是很容易做好,因爲這類系統往往有着複雜的數據庫,上百張的數據表。對每張表都進行數據模擬顯然是不現實的,也是沒有意義的,因爲不是每張表都涉及到大數據量。那麼如何選取不容易遺漏呢?通常通過兩種方式:從設計和業務角度分析表間關係、從現有實際數據量進行分析推測。

  2、確保結果集在正常範圍內。結果集的大小直接影響後續很多工作的性能,如數據排序分組、分頁、程序中的邏輯校驗或者是展現。

  3、數據分佈必須合理,儘量接近真實。數據的分佈,其實也就是數據的真實性,它直接決定了數據庫是否使用索引、選用哪個索引,也就是常說的查詢計劃。不同的查詢計劃也就是不同的數據訪問路徑,性能差別可能會很大。

  這裏主要涉及到的是索引的問題,需要大家對索引的原理有一定的瞭解,索引如何工作、數據庫如何選擇索引、和索引有關的一寫重要概念如區分度(selectivity)等等。

  4、最好的數據來自生產環境。這是顯而易見的,使用真實的數據測出來的結果纔是最準確的。但是絕大多數情況下,我們沒有這樣的好運,可能是客戶禁止、也可能是生產環境數據量比較小。那就只好自己想辦法來模擬了,需要注意的也就是上面說到的幾點。這裏再推薦一種方法,數據翻倍。比如已經有了真實的數據十萬條,但我們需要一百萬條,那就可以通過寫一些SQL或者存儲過程,將現有的數據不斷翻倍(簡單的說,複製到臨時表,根據需要修改一些列,再插回到原表),這樣的數據真實性還是比較高的。

  關於測試數據,我想說的就是以上幾點了。另外再補充上一些相關內容,也是性能測試人員需要關注的。

  ● 重點了解IO的概念,更準確的說應該是物理IO。一般來講,數據庫的瓶頸或者查詢的主要耗時就是IO。所以,數據庫優化的一個重要方向就是儘量減小IO。

  IO是不是隻和數據量(行數)有關呢?舉一個例子:

select co1, col2, col3, col4, col5 from T_AJ

where condition...


  T_AJ數據量有100萬,表中有近200列,此查詢耗時大於10秒。而另一種實現方式,首先將col1-col5以及查詢條件中的幾個列的數據抽取到一張臨時表(#T_AJ)中。然後,

select co1, col2, col3, col4, col5

from #T_AJ where condition...


  臨時表#T_AJ和原數據表有同樣的數據量(行數),但是此查詢卻只需要1秒(暫不考慮抽取到臨時表的耗時),這就是不同IO引起的差異。通常我們使用的數據庫都是行式存儲的,可以簡單的理解爲,一行數據從頭讀到尾,才能進入到下一行。這樣,不管一行中的200列,你只讀取其中的一列還是幾列,其餘的190多列仍然需要一定的IO。在大數據量下,這個性能差異就很明顯了。所以上面的這個例子就是一種典型的優化手段,索引覆蓋也是處理類似問題的典型方法,各位自行了解吧。列式存儲數據庫(如Sybase IQ)之所以性能這麼高,也是同樣的道理。

  ● 儘量深入瞭解這些概念,如執行計劃,基於開銷的估算,統計信息等等。我用一句話來簡單描述:數據庫通過統計信息來估計查詢開銷,統計信息不準時,開銷估計就可能不準確,從而導致選擇了錯誤的執行計劃。

  ● 測試過程中數據的清理。性能測試過程中可能又會生成大量的數據,積累到一定程度又會對性能結果造成影響,所以每一輪測試時都應該清理掉之前測試過程中產生的數據,保證每次測試是在相同的條件下進行的。

  ● 性能測試過程中,如果定位到了某一個查詢或SQL有問題,首先要確認的是數據是否合理。通過查詢計劃來判斷是否按預期進行了查詢,如果不是,查看數據的分佈是否真實。一般數據庫會提供很多種手段來進行驗證。

  最後,本文所寫內容都是針對傳統的行式存儲數據庫的,還請大家注意。

 

性能測試新手誤區(三):用戶數與壓力

 

同樣的項目、同樣的性能需求,讓不同的測試人員來測,會是相同的結果麼?

  假設有這樣一個小論壇,性能測試人員得到的需求是“支持併發50人,響應時間要在3秒以內”,性能測試人員A和B同時開始進行性能測試(各做各的)。

  只考慮發帖這個操作,A設計的測試場景是50人併發發帖,得到的測試結果是平均完成時間是5秒。於是他提出了這個問題,認爲系統沒有達到性能期望,需要開發人員進行優化。

  B設計的測試場景是,50個人在線,並且在5分鐘內每人發一個帖子,也就是1分鐘內有10個人發帖子,最後得到的測試結果是平均完成時間2秒。於是他的結論是系統通過性能測試,可以滿足上線的壓力。

  兩個人得到了不同的測試結果,完全相反的測試結論,誰做錯了?

  或許這個例子太極端,絕對併發和平均分佈的訪問壓力當然是截然不同的,那我們再來看個更真實的例子。

  還是一個小論壇,需求是“100人在線時,頁面響應時間要小於3秒”。A和B又同時開工了,這時他們都成長了,經驗更加豐富了,也知道了要設計出更符合實際的測試場景。假設他們都確認了用戶的操作流程爲“登錄-進入子論壇-(瀏覽列表-瀏覽帖子)×10-發帖”,即每個用戶看10個帖子、發一個帖子。於是他們都錄製出了同樣的測試腳本。

  A認爲,每個用戶的操作,一般間隔30s比較合適,於是他在腳本中的每兩個事務之間加上了30秒的等待(思考時間)。

  B想了想自己看論壇時的情景,好像平均每次鼠標點擊要間隔1分鐘,於是他在腳本中的每兩個事務之間加上了1分鐘的等待。

  他們都認爲自己的測試場景比較接近實際情況,可惜測試結果又是不同的,很顯然A場景的壓力是B的兩倍。那誰錯了呢?或者有人說是需求不明確導致的,那麼你需要什麼樣的需求呢?

  看看我隨手在網上(51testing)找的提問吧,和上面的內容如出一轍。一定有很多的性能測試人員每天接到的就是這種需求,又這樣就開展了測試,結果可想而知。


  這裏我想問幾個問題,希望各位看完了上面的小例子後想一想:

  如果有另一個人和你測同樣的系統,你們的測試結果會一致麼?

  如果不一致,那麼誰是正確的?

  如何證明測試結果是有效的?

  如果你有了一些疑惑,對之前的測試結果少了一些自信,那麼請繼續。

服務器視角 vs. 用戶視角

  性能測試中非常重要的一塊內容就是模擬預期的壓力,測試系統運行在此壓力下,用戶的體驗是什麼樣的。

  那麼壓力是什麼?壓力是服務器在不斷的處理事情、甚至是同時處理很多事情。壓力是服務器直接處理的“事情”,而不是遠在網絡另一端的用戶。

  下圖中,每一個顏色的線段代表一種操作。在任意一個時刻,服務器都知道它有10個事務需要處理,這10個事務也是有10個用戶產生的。但它不知道的是,整個時間段內的所有事務,是由多少個用戶與系統交互而產生的。


  這句話好像有點繞,我再試着更形象的解釋一下。時刻1,10個當前事務是由10個用戶發起的。時刻2,依然是10個正在進行的事務,但可能是完全不同的10個人發起的。在這段時間內,服務器每一個時刻都在處理10個事務,但是參與了這個交互過程(對服務器產生壓力)的人可能會達到上百個,也可能只有最開始的10個。

  那麼,對於服務器來說,壓力是什麼呢?顯然只是每時刻這10個同時處理的事務,而到底是有10個人還是1000個人,區別不大(暫不考慮session等問題)。

  下面再從用戶的視角來看看。實際的情況中,不可能出現很多用戶同一時刻開始進行操作的場景,而是有一定的時間順序的。正如下圖所示,在這個時間段內,一共有23個用戶進行了操作。


  但是服務器能看到這些用戶麼?它知道的只是某一個時間點上,有多少個正在執行的事務。大家可以數一下,此圖中任意時刻的併發事務依然是10個。

  其實這兩個圖描述的本來就是同一個場景,只不過觀察者的視角不同罷了。

  那麼大家想想,在性能需求中最常見到的“併發用戶”到底是指的什麼呢?

併發用戶

  很多使用“併發用戶”這個詞的人,並沒有從服務器視角進行考慮。他們想的是坐在電腦前使用這個系統、對系統產生壓力的人的個數。基於這個原因,我很少使用這個容易讓人誤解的詞彙,而是進行了更細的劃分。主要有這麼幾個:系統用戶數(註冊用戶數)、在線用戶數(相對併發用戶數)、絕對併發用戶數。

  上面幾個例子中所說的“併發用戶”,實際就是在線用戶數。其實我更喜歡叫做相對併發用戶數,因爲這個詞更容易讓人感受到“壓力”。相對併發用戶數指的是,在一個時間段內,與服務器進行了交互、對服務器產生了壓力的用戶的數量。這個時間段,可以是一天,也可以是一個小時。而需求人員必須要描述的,也正是這個內容。

  而絕對併發用戶,主要是針對某一個操作進行測試,即多個用戶同一時刻發起相同請求。可以用來驗證是否存在併發邏輯上的處理問題,如線程不安全、死鎖等問題;也可提供一些性能上的參考信息,比如1個用戶需要1秒,而10個用戶併發卻需要30秒,那很可能就會有問題,需要進行關注,因爲10個用戶請求排隊處理也應該只需要10秒啊。但這種絕對併發的測試,同實際壓力下的用戶體驗關係不大。

  再回到相對併發這個概念上來,它與服務器的壓力到底是什麼關係呢?如果你理解了前面的所有內容,那麼就會知道這兩者其實沒有直接聯繫(當然了,同一個測試用例中,肯定是用戶數越多壓力越大)。也就是說,你得到的這種性能需求,是無法知道服務器到底要承受多大壓力的。

  那麼如何開展性能測試?

如何模擬壓力

  既然我們知道了所謂的壓力其實是從服務器視角來講的,服務器要處理的事務纔是壓力,那麼我們就從這出發,來探尋一下性能測試需要的信息。依然用之前的小論壇爲例,我們需要測試活躍用戶爲500人時,系統的性能是否能還能提供良好的用戶感受。

  假設現在的活躍用戶有50個人(或者通過另一個類似的系統來推算也行),平均每天總的發帖量是50條、瀏覽帖子500次,也就是每人每天發一個帖子、瀏覽十個帖子(爲了方便講解,假設論壇只有這兩個基本功能)。那麼我們就可以推算,活躍用戶達到500時,每天的業務量也會成比例的增長,也就是平均每天會產生500個新帖子、瀏覽帖子5000次。

  進一步分析數據,又發現。用戶使用論壇的時間段非常集中,基本集中在中午11點到1點和晚上18點到20點。也就是說每天的這些業務,實際是分佈在4個小時中完成的。

  那我們的測試場景,就是要用500個用戶在4小時內完成“每人發一個帖子、瀏覽十個帖子”的工作量。

  注意上面的兩處,“平均每天……”、“分佈在4個小時……”。敏感的測試人員應該能發現,這個場景測的是平均壓力,也就是一個系統最平常一天的使用壓力,我喜歡稱之爲日常壓力。

  顯然,除了日常壓力,系統還會有壓力更大的使用場景,比如某天發生了一件重要的事情,那麼用戶就會更加熱烈的進行討論。這個壓力,我習慣叫做高峯期壓力,需要專門設計一個測試場景。

  這個場景,需要哪些數據呢,我們依然可以從現有的數據進行分析。比如上面提到的是“平均每天總的發帖量……”,那麼這次我們就要查到過去最高一日的業務量。“分佈在4個小時”也需要進行相應的修改,比如查查歷史分佈圖是否有更爲集中的分佈,或者用更簡單通用的80-20原則,80%的工作在20%的時間內完成。根據這些數據可以再做適當的調整,設計出高峯期的測試場景。

  實際工作中可能還需要更多的測試場景,比如峯值壓力場景。什麼是峯值壓力呢,比如一個銀行網站,可能會由於發佈一條重磅消息使訪問量驟增,這個突發的壓力也是性能測試人員需要考慮的。

  需要注意高峯期壓力和峯值壓力的區別,高峯期壓力是指系統正常的、預期內壓力的一個高峯。而峯值壓力是指那些不在正常預期內的壓力,可能幾年纔出現一次。

  這裏只是舉了個最簡單的例子,實際工作遠比這複雜的多。需要哪些數據、如何獲取,很可能要取得這些數據就要花費很大的功夫。這其實就涉及到了一個很重要的內容,用戶模型和壓力模型的建立,以後會有專門的文章進行講述。

  爲什麼要花這麼大的精力來收集這些信息呢?是因爲只有通過這些有效的數據,才能準確的去模擬用戶場景,準確的模擬壓力,獲取到更加真實的用戶體驗。只有這樣,“不同的測試人員,測出相同的結果”纔會有可能實現,而且結果都是準確有效的。

要點回顧

  ● 最後通過幾個小問題來總結回顧一下:

  ● 你真的理解“併發用戶”的意義麼?

  ● 什麼是用戶視角和服務器視角?

  ● 什麼是壓力?

  ● 如何模擬預期壓力?

 

性能測試新手誤區(四):一切來自錄製

 

  經常會有性能測試新手問這樣的問題:

  C/S的系統如何錄製,應該選擇什麼協議呢?

  待測系統A的一個功能,是由B系統調用的,也需要搭建B系統的測試環境並對其錄製麼?

  我的回答是,先弄清楚你想測的是什麼?對它而言,壓力又是什麼?

  新手總是想着如何錄製客戶端的操作,如何模擬客戶端的點擊。這種想法應該是受到了主流測試工具影響,性能測試的入門基本都是從工具開始,比如使用最廣的LR,其最方便好用的功能應該就是錄製了。但是需要清楚的是,錄製只是爲性能測試提供便利的一個功能(可以傻瓜式的產生向服務器施加壓力的腳本),錄製本身並不是性能測試的根本或者所必需,能夠產生壓力的那些腳本或是程序纔是關鍵所在。

第一個問題,比如一個即時通訊類的軟件如何測試?

  首先要明確你想測的是客戶端還是服務端,如果是服務端,那麼服務端承受的壓力是什麼呢?

  是每一條消息都要經過服務器麼?

  服務器是要將消息進行存儲,還是僅僅轉發?

  不同的功能,如普通會話和多人會話,從服務端來看的區別是什麼?

  客戶端是如何同服務端通信的,是採用了一些標準的開源協議(如XMPP),還是經過了自己的重新擴展?

  ……

  爲了回答那兩個看似很簡單的問題(想測什麼?壓力是什麼?),其實你需要了解整個系統的運行方式。這些信息完全可以從一些設計文檔或者開發人員的口中獲取到,並不需要你能讀懂源碼。

  如果我知道了這個軟件使用了XMPP協議,一條普通的會話是客戶端向服務器發送了這樣一條信息:


 而多人會話是客戶端發送了這樣的信息:

那麼應該會知道,表面上這些不同的功能,其實只是客戶端發送信息中個別字段的區別而已。那麼我就可以想辦法直接向服務器發送這些信息,讓服務器根據接收信息的內容去完成相應的功能。也許根本沒有必要去想如何錄製客戶端發起一個會話併發送消息這個動作,或者發送文件、羣消息等等其他操作。

  至於如何實現,如果你有編碼能力,可以將開源代碼引入到自己的測試代碼中(需是標準協議),否者可能需要讓程序的開發人員實現一個測試程序。不要不敢開口,開發人員協助進行性能測試是很正常的,而且這種工作量不會很大,只是把程序中的一些代碼封裝成一個可配置可方便調用的執行文件。

  讓開發人員來實現測試工具不丟臉,怕的是你自己不知道測試工具應該實現成什麼樣。(當然,如果自己可以看源碼來實現工具那就更好了)

第二個問題,同樣的,所謂的B系統調用A系統這個動作,是如何實現的?

  會不會只是一個簡單的HTTP請求?

  或者是調用A系統的一個webservice接口?

  你要測的是A的這個功能麼?

  如果是,那我們爲什麼一定要通過B系統來錄製這A的這個功能呢?完全可以直接向A發送請求或者是調用接口(如LR中的webservice協議)。

  至於具體如何做,可能有很多現成的接口測試工具,也可能仍然需要開發人員的協助。比如B與A之間傳遞的數據是經過加密的,那對(黑盒)測試來說就會非常困難,這種情況下,確實有可能通過B來錄製會更簡單。

在51Testing上看到的一個問題,問如何測試一個統計報表的另存爲(excel)功能。

  點這個按鈕後,服務器會生成一張報表,然後彈出瀏覽器的另存爲對話框,保存爲本地文件。提問題的這個人遇到的困難是,LR中好像沒法錄製“另存爲”這個動作。

  之所以會有這樣的問題,根本原因還是沒有理解系統的運行原理,沒有區分哪是服務器、哪是客戶端。

  一般來說,這個過程是這樣的:

  1、點另存爲按鈕時,向服務器發送了一個計算報表的請求,這個請求中會包含一些參數,如報表類型、統計時間等等。

  2、服務器計算完成後,將結果數據返回給客戶端(瀏覽器)。

  3、瀏覽器本身的功能,將數據保存爲一個本地文件。

  (這裏假設了計算過程是另存爲按鈕觸發的,如果是打開頁面時就計算完,那點按鈕時甚至有可能根本沒與服務器進行交互)

如果明白了這個過程,那麼就不會糾結於錄製“另存爲”這種事情了,你要做的只是向服務器發送一個請求,然後接收響應數據。

  那麼就不需要生成本地文件了麼?當然不是,否則怎麼驗證返回的數據沒有問題呢。只不過這個文件的操作需要自己來實現了,創建文件、寫入數據、關閉文件。

最後再總結一下要點:

  ● 理解系統的運行原理

  ● 區分服務端和客戶端

  ● 弄清楚你要測的是什麼,哪些東西其實是可有可無的

  ● 要模擬的是服務器的壓力,而不是客戶端的操作

  ● 錄製只是一種手段,很多情況下並不是最佳選擇

  ● 開發人員的協助是應當的,但前提是你要明確的知道應該如何測試

 

性能測試新手誤區(五):如何提出一個好的性能問題

 

  經常會見到新人提出這樣的性能問題:

  “100用戶時,A操作響應時間達到了XX秒,請修改。”

  面對這樣的問題,開發人員一定會覺得很無助,他們甚至不知道問題是什麼。

  即使從測試人員的角度來看,這也算不上是一個合格的問題。

  那麼一個好的性能問題應該是什麼樣呢?

  好問題要描述清晰

  100個用戶,是指絕對併發操作麼?還是什麼樣的場景?

  是隻測這一個A操作?還是有多個操作在同時進行?

  如果有多個操作,是隻有這一個操作變慢?還是普遍變慢?

  測試環境是什麼樣的?測試數據量是多少?

  也許開發人員理解了詳細的測試場景後,會告訴你,這個場景在業務中是不可能的,或者測試數據量是不合理的。

  好問題要有儘量準確的定位

  只是描述清晰還不夠,要明白什麼是表面現象,什麼纔是問題。

  問題是需要定位才能發現的。

  “100個用戶操作時,A事務的響應時間過長”,這只是一個現象,問題是什麼呢?

  響應慢是慢在哪?是中間件還是數據庫?這是最基本的分層定位。

  是服務器達到了硬件瓶頸麼?如果硬件或操作系統上沒有瓶頸,那麼瓶頸在哪?

  是不是由於一些基本配置問題導致了排隊呢?比如中間件的HTTP線程數和數據庫的連接數。

  如果基本配置沒有問題,那麼再深入一些,是內部的哪些資源產生了爭用和等待麼?

  是哪些SQL引起了數據庫內部資源的爭用呢?應用程序上又是哪個方法在佔用資源呢?

  ……

  定位的越深入,需要的技術能力也就越高。

  好問題應該用最簡單的手段復現

  比如上面的100個用戶,導致了數據庫的一張表的爭用,因此產生了大量鎖等待現象,最終導致了外部的A響應時間過長。但是通過之前的分析和定位,我們發現也許引發問題的那些SQL語句,只來自100用戶中的10個特殊類型的用戶。那麼這個問題就完全可以簡化成用10個用戶去復現,其他90個用戶都是干擾。這樣問題被簡化了,開發人員也就更容易理解問題,對於測試的複測也更加方便。

  不過還是要記住,最終的用戶場景模擬纔是決定性的驗證。

最後再總結一下,性能問題到底應該如何提呢?其實只有一個標準,那就是能讓開發理解問題、找到根本原因並進行修正的就夠了(假設開發人員無所不能)。再進一步深入的分析,可能是爲了減輕開發的一些負擔,也可能是爲了鍛鍊自己的能力,這就不是每個測試人員都會去做的了。

 

性能測試新手誤區(六):性能監控

 

 “數據庫(或中間件)非常慢了,如何監控它的性能”

  “你想得到什麼性能指標?”

  “就是……內部的性能指標”

  收到性能測試人員這樣的問題後,通常會發生上面的對話。

  我的觀點是,準確的說出你想要做什麼,比你會不會做更重要。

  那麼對於性能測試人員來說,”性能監控“這門必修課,該從何下手呢?

  監控什麼

  如果我給你一個黑盒子,告訴你裏面是一部機器,要監控它的性能。你能做到麼?當然不能。因爲你不知道這部機器如何運行,你不知道對它而言性能是什麼。

  性能測試也一樣,說到操作系統,大家都知道性能指標要看CPU、MEMORY、DISK IO以及NETWORK等等。但是到了數據庫和中間件,如果測試人員說不出具體內容,這表明他不知道針對這個對象,性能是什麼,即便把最完整的性能指標擺在面前,恐怕也是沒有意義的。

  當然知識和經驗是一步步積累起來的,但也需要測試人員去主動的學習。從系統體系結構、運行原理到性能監控、性能調優基礎和方法,官方手冊總是最好的教材。

  那麼在沒有掌握這些知識之前,我希望上面的問題是這樣問,“數據庫(或中間件)非常慢了,一般需要監控它的哪些性能指標呢”,得到回答後趕緊翻資料吸收相關的知識。

  過程中的監控

  性能測試新手容易忽略測試過程中的性能監控,而只給出一個最終的測試運行結果。

  比如這個問題,“測試運行3小時後,系統沒有響應,中間件無法連接”。

  對於這樣的問題,期望開發人員如何處理呢?中間件已經無法連接,想獲取到一些內部的性能指標恐怕都已做不到。只有重運行一次,讓開發人員來關注過程中的運行狀況,但這本應是由測試人員來做的。

  如果我們知道,中間件本身無法響應一般可能是因爲這兩個問題:

  JVM堆內存用滿,不停的進行GC,導致響應超慢(但是還沒有OOM,否則就報錯了)

  處理HTTP請求的線程,都被佔用或者鎖住

  那麼我們就可以在測試過程中去監控這兩項數據,跟蹤變化趨勢,直到系統再次無法響應。如果正好其中的一個資源也耗盡了,那麼就可以確認“無法響應“這個現象的直接原因。實際上,這兩個指標基本也是中間件最重要的指標,理應每次測試過程都進行監控和數據採集了。

  監控的層次

  系統的性能表現會涉及到多個層面,比如:

  中間件 -> 中間件操作系統 -> 數據庫 -> 數據庫操作系統 -> 客戶端

  監控時也要着眼於多個層面,這樣纔有可能更接近問題的本質。還是上面那個中間件無法響應的問題,假設我們觀察到了所有HTTP線程都被佔用,也許更進一步我們又會發現這些線程都在執行數據庫的查詢,而這些查詢在數據庫中的狀態依然是running,那就說明更根本的原因是在數據庫層面。這也就是問題的逐步定位。

  全面的監控

  片面的數據不足以說明問題,系統的方方面面常常是相互影響的。

  比如數據庫的CPU佔用很高,並不能證明系統是計算密集型、CPU是瓶頸,也有可能是spinlock的爭用導致了CPU驟增。

  再比如大量的page-in IO可能會使內存出現瓶頸。

  上面的層次問題其實也屬於”全面“的範圍。只有拿到全面的數據,纔有可能分析出正確的結論。

  當然,這又是一個需要積累的過程,如果連spinlock都不知道,又怎麼可能有準確的判斷呢。

  方法還是一個,主動的學習,系統的學習。

 

性能測試新手誤區(七):你需要調優麼

 

  測試人員喜歡在得到某個達不到預期的性能結果後,進行一下“調優”。

  PM有時也會佈置任務,測試完成後“調一個優”。

  一些人貌似有了這種觀念:調優才使性能測試有意義、性能測試的目的就是調優、做調優才能顯出測試人員的水平……

  隨着經驗的增長和對性能更深入的認識,我越來越體會到調優是一個複雜的過程,不是動動嘴、改倆個參數這麼簡單,只有通過科學的方法和紮實的技能才能做好,以至於我使用這個詞的頻率越來越低,因爲不敢輕易說出口……

  在你再一次調優之前,先考慮以下幾個問題:

  爲什麼需要調優

  如果問起這個問題,得到的回答通常是“因爲性能不夠好”,那麼接下來我會問性能不好體現在哪裏?你要調什麼?希望得到什麼結果?

  如果你不能足夠準確的回答第一個“體現在哪裏”的問題,後兩個也一定沒有答案,所謂的調優自然也無從談起。而這第一個問題的答案其實也就是定位的過程。

  舉一個小例子。如果我已經發現數據庫較慢,通過進一步監控又發現了一個cache的spinlock contention這個指標超過了正常的範圍。那麼我會猜測可能是這塊緩存的爭用導致了數據庫的運行狀況變差,針對這個現象我知道可以通過將cache分區來減少爭用,改變配置後再重新測試和監控,這就可以算是一次調優的嘗試。

  但如果你只停留在數據庫慢的這個層面上,又怎麼能進行調優呢?

  所以,需要調優的一個前提是“定位到問題”或者“發現了瓶頸”。

  又有人說了,沒有問題爲什麼不能調優?沒有問題,我們可以讓系統變得更好!

  但是,所謂的“更好”如何衡量?“好”到什麼程度時不需要繼續“好”了呢?

  請記住,瓶頸永遠存在,消滅了一個,就必然會引入另一個。

  調優的目標也不是“沒有瓶頸”,而是系統在其所承受的壓力下,性能表現足夠好,那就夠了!

  “足夠好”其實也就是沒有問題。

  調優調什麼

  理解了上面的內容,這個問題的答案就很明顯,調優必然是針對具體的問題或瓶頸。

  而問題和瓶頸,指的是“性能不好”這個現象的直接原因,而不是那些不痛不癢的其他因素。

  好比奧拓比奧迪跑得慢,最主要的問題在於發動機(不懂車,隨便一說),而不是奧拓車的外型不夠流線、輪胎抓地不夠好……

  如果把精力放在改善外型、輪胎這些方面上,確實會讓奧拓變得更“快”,但是從原問題(比奧迪慢)上來看,這都是沒有意義的。

  至於如何準確的定位出問題,針對問題又如何下手,這就是技術能力,只能依靠不斷的學習、長期的積累了。

  不過依然存在一些比較科學的工作方法,可以讓你儘快的抓住重點。如在系統運行正常時採集一份足夠完整的性能指標作爲基準,當出現狀況時再次採集一份相同的指標,對比其中的差異,從差異處入手。

  經常見到這種人,一聽到數據庫慢,直接加大內存分配、加緩存、加連接數、加大各種資源配置……典型的胡亂“調優”。

  調優的層次

  同一個問題,可能可以從多個方面進行處理。

  一個慢SQL,優化的方式可能是加個索引、綁定緩存、改寫SQL、表分區、甚至是升級硬件。

  資源爭用問題,既可以從配置層面進行優化、減小爭用發生的機率,又可以從程序的實現方式上做改變、從源頭上避免爭用。

  假設多種處理方式,都可以滿足期望,那麼應該從哪個層面下手呢?

  這就需要考慮到工作量、效果、隱患等多種因素,當然也不排除幾種優化共同作用。

  調優有效麼

  這是一個工作方法是否科學的問題。

  每一次試驗,都需要能夠驗證是否有效。有效的保留,無效的則復原。

  除了對原問題的驗證,還必須確認對其他部分是否產生了副作用。理論上這就需要在每一次調優嘗試後,進行一次足夠全面的複測。

  否則,很容易出現“拆東牆補西牆”的問題。

  記住以下幾個要點:

  ● 每次只改變一處。

  ● 每次改變後進行復測。有效的保留,無效的復原。

  ● 不斷的迭代,直到達到預期。

只有真正理解調優的目的,並按照科學的方法行動,你的努力纔會體現出價值。

 

性能問題的分析定位方法

 

主要講一個有效的性能問題應該是什麼樣的,其中提到了定位的問題。但是那篇文章只說了WHAT,並沒有說HOW,只說tester要有明確的定位,卻沒提如何才能定位。實際工作中,我也總是接到這種問題,所以還是要寫一篇關於方法的文章,來說說HOW TO DO。

  以一個典型的WEB系統來舉例,性能問題一般體現在客戶端請求後的響應時間上。在性能測試過程中,即壓力增大到某個程度後,響應時間指標迅速增長。但如那篇文章所說,這隻能叫做一個現象,測試人員需要找到問題所在,HOW TO DO?

  首先要搞清楚,客戶端從發出請求直到看到最終結果,共經歷了哪些過程。如果繪製出一張完整的路徑圖,我們的問題必將定位到這張圖中的某一點上。下面是我畫的一個常見的WEB系統請求的流轉過程。


  客戶發出一個請求,這個請求首先會到達中間件的監聽端口,專門的監聽線程負責接待它,並將它分配給一個空閒的HTTP處理線程。HTTP線程根據請求內容,去執行相應的程序代碼,這裏會涉及程序的內部資源,比如專用的線程、一些隊列等,程序的內部也許還有多個組件,依然可以拆分。再往後,從中間件維護的數據庫連接池中取出一個空閒連接,通過它來與數據庫進行交互。數據庫收到查詢請求後,同樣需要找到一個可用的執行線程,然後才能執行具體的SQL,這裏又會牽扯到很多數據庫的內部資源,如鎖、緩存等等。

  可以看到,從用戶點擊鼠標發出請求,到顯示器上展現出結果,實際是經過了很多處理過程的,這裏的每一個節點出現問題,都會導致我們最終看到的“響應慢”現象出現(這裏不考慮操作系統層面、網絡層面等一些外層的因素)。

  理解了這個過程,只需採取一些科學的方法即可逐漸逼近問題根源,那就是層層剝離、不斷排除。從實際經驗來看,數據庫端最容易出問題,那麼首先就要對其進行驗證。數據庫的性能一般是直接體現在SQL的執行效率上,我們可以捕獲到出現問題時所有執行過的SQL,看其耗時是否正常。如果判斷數據庫端沒有問題,那麼再來到中間件端,這裏又可分爲應用服務器本身和我們自己的程序,可以先看看最容易驗證的部分,應用服務器本身通常維護了一些線程池,很容易可以觀察到它們的使用情況,如果這裏沒有發現異常,那麼問題很可能就出現在我們程序的代碼內部。如果在某一點上發現了異常現象,不要急於斷定這裏就是問題根源,而是要同時觀察與之相鄰節點的表現,一個節點的故障通常也會導致另一節點的異常。

  一個很有效的排查手段就是日誌,在每一個節點上輸出接收到的請求和處理結果的日誌,通常都會很容易的發現問題。

  大致思路就是這樣,總結起來其實很簡單。一是要理解請求處理的完整流程,二是通過科學合理的方法去分析。

  最後推薦個比較典型的問題排查過程供大家體會,超級奇怪的“黑色10秒鐘”。我自己也有一些這種很有代表性的分析過程,有時間整理好也貼上來。

 

 ***********************************************

`弄清目的後請開發協助。

`日常壓力&高峯期壓力&峯值壓力

`spinlock中文譯名爲“自旋鎖”。是專爲防止多處理器併發而引入的一種鎖。使得當我們在修改某個重要的資料結構時,不能被中斷,即使被中斷了,這個資料結構由於還沒修改完,別的行程也都不能去讀取和修改它。

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章