關于性能測試你可能需要知道這些東西!
性能測試已經是一個老生常談的話題了,不同的項目或多或少都會涉及到,但是每個人的經驗肯定有所不同。今天我想從以下幾個方面分享一下我認為關于性能測試需要重視的要點。
1. 性能測試的需求
當問到性能測試的需求,我們的客戶有時候會回答,“我們要支持20000個用戶同時在線”,或者“每天有10000個用戶同時訪問這個網站”,更有甚者“我們也不知道,越多越好吧”。這種情況下我們應該怎么辦呢?
當用戶說“我們有10000個用戶同時訪問這個網站”的時候,看似我們的需求已經很“明確”了。真的很明確了嗎?就拿這個例子來說,這10000個用戶都在干什么呢?假想下,可能有5000個用戶在瀏覽靜態頁面,2000個在創建表單,1000個在做查詢,還有... 真正產生壓力的用戶是誰呢?這恐怕不能單單從10000個用戶同時訪問這個網站得到結果。
之前做過一個項目,客戶為某機場,他們為用戶提供免費的WiFi服務,但是提供在WiFi的同時,會在不同的頁面播放廣告。后臺有一個廣告管理系統,可以做一些配置,根據優先級來投放廣告。這其中涉及到一些復雜的算法,主要是投放廣告的比例。當然機場還有很多物料服務器,主要是用來存放廣告的圖片等等。當時用戶給的性能需求也就一句話,“我們每天大概有xxxxxx個用戶連接我們的WiFi”。那怎樣來做性能測試呢?
“多少個用戶連接WiFi”其實只是一個最表面的現象,在連接WiFi的同時,其實系統做了很多事情。首先連接WiFi的時候會去訪問分發服務器,確定要播放哪幾個廣告,其次會根據分發的廣告,去物料服務器上找相應的資源,然后打點把廣告訪問的歷史數據記錄到數據庫中。這是能聯想到的一些最基本的后臺操作,每一個行為都有可能成為一個瓶頸,都需要去認真考慮。
所以在考慮性能需求的時候,一定要清楚背后的邏輯是什么,同時需要分析用戶活動,從而確認系統的性能測試目標。
歷史數據
“性能現在的需求也不是很明確,但我們有原來的老系統,能幫我們看下嗎?”
對于性能測試來說,如果有很詳細的歷史數據,這將是一個非常珍貴的數據源,我們可以從中分析出很詳細用戶行為。之前我們做過一個項目,性能測試的需求基本上就是從歷史數據中得到的。我們對數據庫進行了很詳細的分析,從而設計性能測試用例,這其中主要包含系統的哪些service承受了壓力、壓力是多大、用戶量是多大等等。
需要特別注意的是,如果對于業務的了解不夠深,很容易導致場景的設計缺失,從而導致測試的場景和實際的場景有所偏差。比如分析某張表,分析出系統有10000個插卡拔卡記錄,有的人可能直接就開始寫腳本了,模擬一個用戶每天做10000次插卡拔卡的操作。殊不知,這10000次插卡和拔卡的操作是4000個用戶完成的...而性能的瓶頸很有可能就在用戶的管理,而不是插卡拔卡產生的壓力。
所以建議在做歷史數據分析的時候,一定盡量把場景分析全面,并且需要去了解真正的業務,才可以盡量減少分析的錯誤。
不明確的需求
“我們也不知道需求是什么,你們看著辦吧。”
這種情況通常出現在一個新的項目,客戶對上線后的用戶體量并沒有很好的認知。我們應該怎么做呢?
通常我們會對系統進行負載測試,就是在被測系統上不斷增加壓力,直到性能指標(如響應時間)超過預期或者某種資源已經快達到飽和狀態,這個時候我們基本就可以確定系統的瓶頸是什么、支持多大的吞吐量。再通過一段時間的穩定性測試,讓系統在一定的時間內(比如一周)維持一定的壓力,去查看相應的性能指標。
這樣,我們就可以告訴我們的用戶,系統現在支持多大的用戶訪問量、吞吐量是多少。
當然,現在提到的都是客戶的需求,對于性能測試本身來說,我們也有一些明確的需求,也就是我們通常提到的index,下面我會繼續深入討論這個問題。
2. 定義性能測試的指標
通常來說我們會關注如下的性能測試指標。
響應時間:比較熟悉的就是2-5-8原則(據統計當網站慢一秒就會流失十分之一的客戶),通常來說,2到5秒,頁面體驗會比較好,5到8秒還可以接受,8秒以上基本就很難接受了。但是有的項目也會例外,比如從海量的數據中去查詢某些數據,或者生成報告(年度報告),這種可能就不太適合2-5-8原則,但是前提是要管理好客戶的期望。
吞吐量:指的是在單位時間內客戶端和服務器成功傳送數據的數量
并發:客戶/服務端同一批用戶同時執行一個操作的數量
資源使用率:通常來說,我們關注的資源就是幾大塊:內存、CPU、I/O和網絡
成功率:比如在某些情況下,API調用的成功率
當了解了我們所需要關注的性能指標,就可以來定義具體的性能測試指標了。
我之前做一個比較大的項目的性能測試,系統提供很多服務,有web service,有windows的services,基本上每個services都是單獨部署在一臺window的服務器上,所有的services都連到同一個數據庫。由于這個系統并不存在網頁,所以我們并沒有把頁面加載這些考慮在內。我們從歷史數據中首先了解到了系統需要滿足的并發量,針對每個service去做相應的壓力測試,并且定義對應的性能測試指標。如下圖:
上圖就是對于web service性能測試的指標和結果,這個結果是我們基于每秒有7個Post請求+3個get請求而產生的。
這其中的性能指標包含了我們對這個service的單獨的內存監控、CPU監控,以及成功率的監控,還有相應的原因分析。通常來說,對于內存、CPU等的占用率,業界都有很共識的標準,大家可以拿來作為參考,由于我們服務器是8g內存,8核CPU,所以表現還是相當不錯的。
其他的service也是類似的,我們考察的點主要在于CPU,內存的占用率,還有成功率。
由于網絡一開始我們就認為不是瓶頸(都在內網),所以我們并沒有把網絡相應的指標加進去。
需要特別注意的數據庫server,和其他windows service或者web service不一樣,對于DB server我們需要特別關注的是I/O,數據庫的瓶頸一般都是出現在I/O上面。
在項目中我們往往還要自定義一些其他的指標,來查看某些特定的性能。比如:
為了分析方便,我們在一些service的關鍵方法上都加上時間戳,便于去做trouble shooting。于是我們有了一下的指標,圖一是某個方法的平均調用時間,圖二是我們計算出的最慢調用方法的top10:
3. 如何trouble shooting
剛才提到了性能測試中的一些相應的指標,當我們發現某些指標不正常的時候,我們應該怎樣去做呢?
性能測試的指標往往又是相互關聯的,當遇到問題時,我們需要從這些指標的結果中去尋找真正的root cause,這也是性能測試最重要的點之一。廢話少說,我們直接來看幾個例子吧:
內存泄露是性能測試中很常見的一個點,比如下圖,很明顯能看到有一個內存上升的趨勢,這種情況下很可能就有內存泄露的情況。但是也有例外,比如是C#或者Java寫的代碼,因為內存回收是垃圾回收器自己的行為,不像C語言那樣需要手動回收,所以即使內存在一段時間內有上升的趨勢,但是只要能回到原點,就不存在內存泄露的現象。
內存泄露很多時候并沒有很明顯的征兆,有一次客戶抱怨服務掛掉了,這個服務之前有好幾個月都運行的好好的,怎么說掛就掛呢,然后我們對系統日志做了很詳細的分析,發現就是內存泄露惹的禍。每天內存泄露一點點,到第三個月的時候才導致服務崩潰,這在短期的性能測試中就很難發現。
下圖是當時我們在做性能測試的時候發現的問題,很明顯內存在一段時間內直接從200多MB升到了500多MB,很有可能存在內存泄露的情況。怎樣trouble shoooting呢?
這是一個很常見的問題,單單看現象,其實我們并不知道系統是哪里出的問題,有可能是網絡慢,有可能是內存出現了瓶頸,也有可能是I/O的問題... 怎樣定位呢?
首先我們還是找到相應的apiserver,通過性能測試的報告,我們發現了下面的問題,message queue隨著時間的變化增長特別快,這個時候看API server本身的內存和CPU并沒有什么問題,那么問題到底處在哪呢?
這個時候其實很容易就聯想到是數據庫出現了問題,對比兩個不同的版本,發現我們對數據庫的存儲過程有所更改,最終發現是存儲過程的更改導致了某個索引失效,最終反映到API就是速度明顯變慢。添加索引后問題得到了解決。一般來說,當我們在修改數據庫的時候一定要特別小心,很可能一個小的改動就會導致系統性能的急劇下降。
對于性能測試來說,往往我們發現的問題都是表象上的問題,比如頁面反應很慢。但這有可能是多種原因導致的,需要去做深入的分析。這也要求我們在做性能測試時去收集足夠的信息,以支撐分析,同時借助一些第三方工具,才能真正定位到問題。
4. 關于數據庫
其實性能測試我前面已經提到了很多,為什么還要把數據庫單拿出來說呢?我們來看看數據庫服務器的特殊之處:
我們在進行服務器的內存的測試的時候,如果是普通的APP server,當我們對內存進行監控時,通常都是有一個metrics, 比如某個APP的service的內存使用量不能超過總量的百分之多少,對于整個sever來說,通常也會有比較多的內存剩余。
而當我們去查看一個數據庫server的時候,會發現可用的內存量通常只有10M或者5M(取決于你的配置)...... 而當你把數據庫的內存增加一倍,可用的內存通常還是只有10M左右,這是什么原因呢?
其實這與數據庫本身的工作原理有關系,數據庫中io操作的基本單位為頁,當數據庫執行一條語句,比如一條查詢語句,它會先從物理磁盤中把相應的頁加載到內存,然后再進行操作。
因為數據庫本身就在不停的讀寫,所以數據庫內存當中會緩存各種各樣的數據,為了更快的讀寫,數據庫會有算法去維護這些內存中的數據,以保證盡可能的使得數據都是從內存中獲得,而不是從物理內存中得到(內存的訪問速度是納秒級,硬盤是微秒級)。所以一般來說,數據庫會基本用光所有的內存。
這就是為什么數據庫會吃內存了,這與其工作原理有關系,只要能保證系統能正常運行就可以了,其他的內存都可以用來緩存數據。
死鎖通常是指爭搶資源不當,讓雙方因為對方掌握了自己的資源而無限期的等下去。如下圖所示:
發生死鎖的原因很多,大部分是由于事務之間對資源訪問順序的交替,或者并發修改統一記錄導致的,數據庫對待死鎖有著不同的策略,對于SQL server來說,它會隨機殺掉其中的一個,至少保證另外一個事務的正常運行;而對于Oracle來說,它會對兩個事務進行一個評估,會殺掉它認為不那么重要的一個。
所以我們在數據層面,需要去監控死鎖的發生情況,一般來說,死鎖是不可避免的,但是一旦死鎖發生頻率很多,必定會影響到業務。
我們可以用很多工具去監控死鎖,比如SQL Profile。對于死鎖的修正也是對于高并發的事務,盡量減少長度;把鎖的優先級調整低一些(用低隔離級別);按同一順序訪問對象,盡量避免事務中的用戶交互。
因為對于數據庫來說,最重要的就是讀寫的操作,磁盤對于數據庫來說是非常重要的。
現在好多數據庫都是直接放在云盤上的,云盤上的磁盤有著自己的結構,但是很多年前,如果是自己的服務器,我們還要考慮到磁盤陣列,來保證磁盤的效率和安全性。
對于磁盤來說,我們通常會從讀寫方面來衡量,有幾個比較通過的指標可以用來衡量數據庫磁盤的性能,比如Average Disk queue lenth,數據生命周期等等。
另外值得一提的是數據庫的碎片整理。當數據庫讀寫一段時間之后,由于頻繁的插入數據,會導致數據并不是按照順序排列在磁盤上面,這樣當我們在查相關數據的時候,磁盤往往要去不同的區域查找數據,導致性能降低,這個時候我們很有必要去運行磁盤的碎片整理,來保證數據庫性能。
但是這個job本身就很占磁盤的I/O,所以盡量選擇系統不忙的時候進行。
相信索引是大家很熟悉的一個話題了,當數據量很小時,不建索引,進行全表掃描的的性能尚可接受。但是數據量大時,必須借助索引。所以索引的適當與否,是性能好壞的關鍵。
這條語句這樣執行與創建的索引有關系,如果沒有索引就需要進行全表掃描,這樣加載到內存當中的頁在數據量很大的情況下就相當多了。如果建立了適當的索引,可能只需要加載幾頁內存就可以了。
我們也需要再適當的時候reindex索引,原因就是如果索引在物理存儲上不連續,也會導致性能的下降,這與磁盤的碎片整理是一個道理。
一般來說,如果系統設計合理,最終的瓶頸都會出現在數據庫上,而我們在做性能測試時,也需要了解數據庫的特殊之處,去更好的做性能測試。
5. 關于性能測試的工具
對于市面上的那么多性能測試工具,怎樣選擇呢?
性能測試的工具實際上有很多,能列出來的比如Jmeter、Loadrunner,Galtling等等,這取決于很多方面:
需要測試測試服務端的性能?還是前端的性能?或者是mobile端的性能?后端的話可以選擇Jmeter、Loadrunner或者Gatling。前端的話可以選擇比如Fiddler、httpWatch等,手機端可以選用GT或者APT等。
項目的成本,很多性能測試的工具是收費的,也有很多是開源的,需要結合具體的項目進行考慮。
我們也可以自己寫腳本來完成性能測試,只要能滿足要求項目的要求就可以。但是通常來說使用已有的工具一般會產生比較好的測試報告,除非一些特殊情況,比如某些協議的特殊性,或者很簡單的一些場景等,一般來說還是建議使用市面上已有的工具。
使用工具的同時,盡量保證測試系統和測試的腳本在同一個網絡里面,這樣測試出來的結果才有意義。
寫在最后
總的來說,性能測試其實是一個很復雜的過程。需要結合不同的方面正確分析需求,根據需求設計出合理的測試場景,定義出性能測試的指標,并且在測試中選擇合適的工具進行測試,并且結合測試的多項結果進行分析和trouble shooting。
本文轉載自微信公眾號JavaGuide
云性能測試服務 CPTS 數據庫
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。