併發用戶數、響應時間、系統吞吐量,這三個名詞的含義可能就已經讓你感覺雲裏霧裏了,因此我會通過一個我們日常生活中的體檢爲例,再來解釋一下它們到底是什麼,以及它們之間的關係和約束。
你先來想象這樣一個場景:假設你找了一份新工作,入職前需要到體檢中心完成入職體檢。
在體檢中心做檢查的過程,通常是先到前臺登記個人信息並領取體檢單,然後根據體檢單的檢查項目依次完成不同科室的檢查。
假設一共有5個科室,每個科室有3個候診室,你發現體檢中心有很多人都在做檢查,那麼你一般會選擇先做排隊人數較少的檢查項目,直至完成5個科室的全部檢查,最後離開體檢中心。
現在,我們做個類比:把整個體檢中心想象成一個軟件系統,從你進入體檢中心到完成全部檢查離開所花費的時間就是響應時間,而同時在體檢中心參加體檢的總人數就是併發用戶數,那麼系統吞吐量就可以想象成是單位時間內完成體檢的人數,比如每小時100人。
如果你到達體檢中心的時間比較早,這時人還很少,5個科室都不用排隊,那麼你就能以最短的時間完成體檢。
也就是說,當系統的併發用戶數比較少時,響應時間就比較短;但是由於整體的併發用戶數少,所以系統的吞吐量也很低。從中,我們可以得出這樣的結論:
當系統併發用戶數較少時,系統的吞吐量也低,系統處於空閒狀態,我們往往把這個階段稱爲 “空閒區間”。
如果你到達體檢中心時,這裏的人已經比較多了,只有部分科室不需要排隊,但好在每個科室都有3個候診室同時進行檢查,所以排隊時間不會很長,你還是可以在較短的時間完成體檢。
也就是說,當系統的併發用戶數比較多時,響應時間不會增加太多,因此係統的整體吞吐量也隨着併發用戶數的變大而變大的。從中,我們可以得出這樣的結論:
當系統整體負載並不是很大時,隨着系統併發用戶數的增長,系統的吞吐量也會隨之呈線性增長,我們往往把這個階段稱爲 “線性增長區間”。
但是,當體檢中心的人越來越多時,每個科室都需要排隊,而且每個科室的隊伍都很長,你每檢查完一個項目都要花很長時間去排隊進行下一個檢查項目。這樣一來,你完成體檢的時間就會明顯變長。
也就是說,系統的併發用戶數達到一定規模時,每個用戶的響應時間都會明顯變長,所以系統的整體吞吐量並不會繼續隨着併發用戶數的增長而增長。從中,我們可以得出這樣的結論:
隨着系統併發用戶數的進一步增長,系統的處理能力逐漸趨於飽和,因此每個用戶的響應時間會逐漸變長。相應地,系統的整體吞吐量並不會隨着併發用戶數的增長而繼續呈線性增長。我們往往把這個階段稱爲系統的“拐點”。
最糟糕的情況來了,如果體檢中心的人繼續增加,你會發現連排隊、站人的地方都沒有了,所有人都被堵在了一起,候診室中檢查完的人出不來,排隊的人又進不去。
也就是說,系統的併發用戶數已經突破極限,每個用戶的響應時間變得無限長,因此係統的整體吞吐量變成了零。換言之,此時的系統已經被壓垮了。從中,我們可以得出這樣的結論:
隨着系統併發用戶數的增長,系統處理能力達到過飽和狀態。此時,如果繼續增加併發用戶數,最終所有用戶的響應時間會變得無限長。相應地,系統的整體吞吐量會降爲零,系統處於被壓垮的狀態。我們往往把這個階段稱爲“過飽和區間”。
通過這個類比,相信你已經對併發用戶數、響應時間和系統吞吐量理解得更透徹了,對於它們之間的關係和約束,也都瞭然於胸了。
只有理解了這些主要性能指標之間的約束關係,我們才能在實際的性能測試實踐中設計有的放矢的性能測試場景。比如,後端性能測試的測試負載,我們一般只會把它設計在“線性增長區間”內;而壓力測試的測試負載,我們則會將它設計在系統“拐點”上下,甚至是“過飽和區間”。
那麼,接下來讓我們一起來看一下性能測試的方法都有哪些。
常用的七種性能測試方法
根據在實際項目中的實踐經驗,我把常用的性能測試方法分爲七大類:後端性能測試(Back-end Performance Test)、前端性能測試(Front-end Performance Test)、代碼級性能測試(Code-level Performance Test)、壓力測試(Load/Stress Test)、配置測試(Configuration Test)、併發測試(Concurrence Test),以及可靠性測試(Reliability Test)。接下來,我將詳細爲你介紹每一種測試方法。
第一,後端性能測試
其實,你平時聽到的性能測試,大多數情況下指的是後端性能測試,也就是服務器端性能測試。
後端性能測試,是通過性能測試工具模擬大量的併發用戶請求,然後獲取系統性能的各項指標,並且驗證各項指標是否符合預期的性能需求的測試手段。
這裏的性能指標,除了包括併發用戶數、響應時間和系統吞吐量外,還應該包括各類資源的使用率,比如系統級別的CPU佔用率、內存使用率、磁盤I/O和網絡I/O等,再比如應用級別以及JVM級別的各類資源使用率指標等。
由於需要模擬的併發用戶數,通常在“幾百”到“幾百萬”的數量級,所以你選擇的性能測試工具,一定不是基於GUI的,而是要採用基於協議的模擬方式,也就是去模擬用戶在GUI操作的過程中實際向後端服務發起的請求。
只有這樣才能模擬很高的併發用戶數,儘可能地模擬出真實的使用場景,這也是現在所有後端性能測試工具所採用的方法。
根據應用領域的不同,後端性能測試的場景設計主要包括以下兩種方式:
- 基於性能需求目標的測試驗證;
- 探索系統的容量,並驗證系統容量的可擴展性
第二,前端性能測試
前端性能測試並沒有一個嚴格的定義和標準。
通常來講,前端性能關注的是瀏覽器端的頁面渲染時間、資源加載順序、請求數量、前端緩存使用情況、資源壓縮等內容,希望藉此找到頁面加載過程中比較耗時的操作和資源,然後進行有針對性的優化,最終達到優化終端用戶在瀏覽器端使用體驗的目的。
目前,業界普遍採用的前端測試方法,是雅虎(Yahoo)前端團隊總結的7大類35條前端優化規則,你可以通過雅虎網站查看這些規則,以及對各規則的詳細解讀。
我在這裏列出了其中幾個最典型也是最重要的規則,來幫助你理解前端性能測試優化的關注範圍。
- 減少http請求次數:http請求數量越多,執行過程耗時就越長,所以可以採用合併多個圖片到一個圖片文件的方法來減少http請求次數,也可以採用將多個腳本文件合併成單一文件的方式減少http請求次數;
- 減少DNS查詢次數:DNS的作用是將URL轉化爲實際服務器主機IP地址,實現原理是分級查找,查找過程需要花費20~100ms的時間,所以一方面我們要加快單次查找的時間,另一方面也要減少一個頁面中資源使用了多個不同域的情況;
- 避免頁面跳轉:頁面跳轉相當於又打開一個新的頁面,耗費的時間就會比較長,所以要儘量避免使用頁面跳轉;
- 使用內容分發網絡(CDN):使用CDN相當於對靜態內容做了緩存,並把緩存內容放在網絡供應商(ISP)的機房,用戶根據就近原則到ISP機房獲取這些被緩存了的靜態資源,因此可以大幅提高性能;
- Gzip壓縮傳輸文件:壓縮可以幫助減小傳輸文件的大小,進而可以從網絡傳輸時間的層面來減少響應時間;
第三,代碼級性能測試
代碼級性能測試,是指在單元測試階段就對代碼的時間性能和空間性能進行必要的測試和評估,以防止底層代碼的效率問題在項目後期才被發現的尷尬。
如果你從事過性能測試相關的工作,一定遇到過這樣的場景:系統級別的性能測試發現一個操作的響應時間很長,然後你要花費很多時間去逐級排查,最後卻發現罪魁禍首是代碼中某個實現低效的底層算法。這種自上而下的逐級排查定位的方法,效率通常都很低,代價也很高。
所以,我們就需要在項目早期,對一些關鍵算法進行代碼級別的性能測試,以防止此類在代碼層面就可以被發現的性能問題,遺留到最後的系統性能測試階段才被發現。
但是,從實際執行的層面來講,代碼級性能測試並不存在嚴格意義上的測試工具,通常的做法是:改造現有的單元測試框架。
最常使用的改造方法是:
-
將原本只會執行一次的單元測試用例連續執行n次,這個n的取值範圍通常是2000~5000;
-
統計執行n次的平均時間。如果這個平均時間比較長(也就是單次函數調用時間比較長)的話,比如已經達到了秒級,那麼通常情況下這個被測函數的實現邏輯一定需要優化。
這裏之所以採用執行n次的方式,是因爲函數執行時間往往是毫秒級的,單次執行的誤差會比較大,所以採用多次執行取平均值的做法。
第四,壓力測試
壓力測試,通常指的是後端壓力測試,一般採用後端性能測試的方法,不斷對系統施加壓力,並驗證系統化處於或長期處於臨界飽和階段的穩定性以及性能指標,並試圖找到系統處於臨界狀態時的主要瓶頸點。所以,壓力測試往往被用於系統容量規劃的測試。
還有些情況,在執行壓力測試時,我們還會故意在臨界飽和狀態的基礎上繼續施加壓力,直至系統完全癱瘓,觀察這個期間系統的行爲;然後,逐漸減小壓力,觀察癱瘓的系統是否可以自愈。
第五,配置測試
配置測試,主要用於觀察系統在不同配置下的性能表現,通常使用後端性能測試的方法:
-
通過性能基準測試(Performance Benchmark)建立性能基線(Performance Baseline);
-
在此基礎上,調整配置;
-
基於同樣的性能基準測試,觀察不同配置條件下系統性能的差異,根本目的是要找到特定壓力模式下的最佳配置。
這裏需要注意的是,“配置”是一個廣義配置的概念,包含了以下多個層面的配置:
- 宿主操作系統的配置;
- 應用服務器的配置;
- 數據庫的配置;
- JVM的配置;
- 網絡環境的配置;
- …
第六,併發測試
併發測試,指的是在同一時間,同時調用後端服務,期間觀察被調用服務在併發情況下的行爲表現,旨在發現諸如資源競爭、資源死鎖之類的問題。
談到併發測試,我就不得不和你說說“集合點併發”的概念了,它源於HP的LoadRunner,目前已經被廣泛使用了。那,到底什麼是“集合點併發”呢?
假設我們希望後端調用的併發數是100,如果直接設定100個併發用戶是無法達到這個目標的,因爲這100個併發用戶會各自執行各自的操作,你無法控制某一個確定的時間點上後端服務的併發數量。
爲了達到準確控制後端服務併發數的目的,我們需要讓某些併發用戶到達該集合點時,先處於等待狀態,直到參與該集合的全部併發用戶都到達時,再一起向後端服務發起請求。簡單地說,就是先到的併發用戶要等着,等所有併發用戶都到了以後,再集中向後端服務發起請求。
比如,當要求的集合點併發數是100時,那麼前99個到達的用戶都會等在那裏,直到第100個用戶到了,才集中向後端服務發起請求。當然,實際達到服務器的併發請求數,還會因爲網絡延遲等原因小於100。
所以,在實際項目中,我建議在要求的併發數上進行適當放大,比如要求的併發數是100,那我們集合點併發數可以設置爲120。
第七,可靠性測試
可靠性測試,是驗證系統在常規負載模式下長期運行的穩定性。
雖然可靠性測試在不同公司的叫法不同,但其本質就是通過長時間模擬真實的系統負載來發現系統潛在的內存泄漏、鏈接池回收等問題。
由於真實環境下的實際負載,會有高峯和低谷的交替變化(比如,對於企業級應用,白天通常是高峯時段,而晚上則是低峯時段),所以爲了儘可能地模擬出真實的負載情況,我們會每12小時模擬一個高峯負載,兩個高峯負載中間會模擬一個低峯負載,依次循環3-7天,形成一個類似於“波浪形”的系統測試負載曲線。
然後,用這個“波浪形”的測試負載模擬真實的系統負載,完成可靠性測試。同樣地,可靠性測試也會持續3-7天。
聊完了常用性能測試方法的種類後,我們再來簡單看一下性能測試的四大應用領域,以及每個應用領域都會使用哪些性能測試方法。
性能測試的四大應用領域
不同的性能測試方法適用於不同的應用領域去解決不同的問題,這裏“不同的應用領域”主要包括能力驗證、能力規劃、性能調優、缺陷發現這四大方面。每個應用領域可以根據自身特點,選擇合適的測試方法。
第一,能力驗證
能力驗證是最常用,也是最容易理解的性能測試的應用領域,主要是驗證“某系統能否在A條件下具有B能力”,通常要求在明確的軟硬件環境下,根據明確的系統性能需求設計測試方案和用例。
能力驗證這個領域最常使用的測試方法,包括後端性能測試、壓力測試和可靠性測試。
第二,能力規劃
能力規劃關注的是,如何才能使系統達到要求的性能和容量。通常情況下,我們會採用探索性測試的方式來了解系統的能力。
能力規劃解決的問題,主要包括以下幾個方面:
- 能否支持未來一段時間內的用戶增長;
- 應該如何調整系統配置,使系統能夠滿足不斷增長的用戶數需求;
- 應用集羣的可擴展性驗證,以及尋找集羣擴展的瓶頸點;
- 數據庫集羣的可擴展性驗證;
- 緩存集羣的可擴展性驗證;
- …
能力規劃最常使用的測試方法,主要有後端性能測試、壓力測試、配置測試和可靠性測試。
第三,性能調優
性能調優,其實是性能測試的延伸。在一些大型軟件公司,會有專門的性能工程(Performance Engineering)團隊,除了負責性能測試的工作外,還會負責性能調優。
性能調優主要解決性能測試過程中發現的性能瓶頸的問題,通常會涉及多個層面的調整,包括硬件設備選型、操作系統配置、應用系統配置、數據庫配置和應用代碼實現的優化等等。
這個領域最常用的測試方法,涵蓋了我在上面分享的七大類測試方法,即後端性能測試、前端性能測試、代碼級性能測試、壓力測試、配置測試、併發測試和可靠性測試。
第四,缺陷發現
缺陷發現,是一個比較直接的應用領域,通過性能測試的各種方法來發現諸如內存泄露、資源競爭、不合理的線程鎖和死鎖等問題。
缺陷發現,最常用的測試方法主要有併發測試、壓力測試、後端性能測試和代碼級性能測試。
上面這些內容就是性能測試的常用方法和應用領域了,我用一張表彙總了各個應用領域需要用到的測試方法,希望可以幫助你記憶、理解。
能力驗證 | 能力規劃 | 性能調優 | 缺陷發現 | |
---|---|---|---|---|
後端性能測試 | √ | √ | √ | √ |
前端性能測試 | √ | |||
代碼級性能測試 | √ | √ | ||
壓力測試 | √ | √ | √ | √ |
配置測試 | √ | √ | ||
併發測試 | √ | √ | ||
可靠性測試 | √ | √ | √ |
總結
今天我通過一個生活中“體檢”的實例,和你分享了併發用戶數、響應時間和系統吞吐量三者之間的關係:
- 當系統整體負載並不是很大時,隨着併發用戶數的增長,系統的吞吐量也會隨之線性增長;
- 隨着併發用戶數的進一步增長,系統處理能力逐漸趨於飽和,因此每個用戶的響應時間會逐漸變長,相應地,系統的整體吞吐量並不會隨着併發用戶數的增長而繼續線性增長。
- 如果併發用戶數再繼續增長,系統處理能力達到過飽和狀態,此時所有用戶的響應時間會變得無限長,相應地,系統的整體吞吐量會降爲零,系統處於被壓垮的狀態。