某項目在上線前的APT(Application Performance Testing應用程序性能測試)過程當中發現性能問題,性能測試結果影響是否上線,緊急求助外部項目組技術專家。數據庫
因分屬不一樣項目,只能經過項目組提供的信息進行分析。小程序
第一輪評審緩存
現象網絡
根據APT性能監控截圖,左圖爲併發用戶數和CPU使用率,右圖爲單獨的CPU使用率狀況。APT測試情景爲併發用戶數以5分鐘爲週期進行增長,增長用戶數25人,在40分鐘後達到最終200併發用戶並保持1小時200用戶活動狀態。架構
很明顯看出用戶穩定後CPU使用率還在持續增加,懷疑有內存泄露問題。併發
分析ide
第一輪咱們拿到的是API源代碼,日誌裏面出現outOfMemory錯誤,檢查一遍發現API控制器方法中建立了HttpClient實例。詢問開發組回覆是由於每次請求URL不一樣,根據經驗推薦採用HttpWebRequest替換調HttpClient。同時咱們調查是不是由HttpClient引發的內存泄漏問題。工具
由Google搜索結果HttpClient確實有內存泄漏的報告,咱們着手寫了一個小程序比較HttpClient和HttpWebRequest性能,並經過JMeter在本地進行性能測試。性能
HttpClient和HttpWebRequest性能比較測試
測試環境
測試URL: https://www.baidu.com/#{number} (number變量爲隨機或遞增以防止HTTP緩存干擾性能對比結果)
測試節奏:10秒週期,併發用戶從1到200增加
測試結果(內存使用量)
圖1: HttpClient (GetAsync)
圖2: HttpWebRequest (請忽略結尾處由網絡鏈接問題出現的凸起)
結論
將HttpClient更換使用HttpWebRequest,但根據HttpClient內存使用陡增幅度估計還有其它問題,通知開發組繼續調查並提供相關資料。
第二輪評審
現象
比較IIS內存使用和SQL Server的內存使用發現相同的增加趨勢,猜想瓶頸出如今數據庫查詢中(若是是拒絕訪問數據庫不會出現內存增加,必定是已經鏈接了數據庫併產生查詢問題致使)。
推薦增長查詢操做日誌得到查詢執行時間,安裝數據庫性能監視工具(可以使用Windows Server自帶的Performance Monitor或者第三方工具如AppDynamic),查看查詢的執行計劃(Execution Plan)。
圖3: SQL Server – 內存 - % committed Bytes (內存使用)
圖4: MS IIS – 內存 - % Committed Bytes (內存使用)
同時通過了解API還會調用上游系統的API(API嵌套),因此考慮檢查日誌是否存在因上游API瓶頸致使調用失敗,致使異常阻塞請求進程。也會出現相同的現象,開發組着手調查。
上游API問題經過調整系統配置消除瓶頸,但SQL Server性能問題還無任何頭緒。只能安排時間一塊兒評審數據庫及相應查詢性能問題。
第三輪評審
背景:
測試總時長1小時40分:從最開始每隔1分鐘增加5個併發用戶,40分鐘左右併發數加到200,而後維持併發用戶不變,又執行1小時
現象:
達到200併發後的20分左右時, CPU的使用率達到30% 左右以後保持相對平穩的比例,可是在這以後的執行過程當中 request queued 曲線出現排隊現象, Thread Count 曲線出現忽然增加的狀況,而且同是response time 翻倍增加。
上次報告沒有HTTP 5xx錯誤,本次出現HTTP 5xx錯誤,27日錯誤數量激增。
程序中有從上百萬條數據中抽取數據生成級聯選擇(下拉菜單)的UI元素。
程序中使用了Http Cache,但在準備Cache數據的邏輯中沒有鎖處理,數據準備時間過長,就會形成期間大量請求訪問數據庫。
性能測試報告中SQL Server也顯示出週期性達到100% CPU利用率,引起數據庫鏈接超時,同時應用程序出現GATEWAY_TIMEOUT。
System.Data.Entity.Core.EntityException: The underlying provider failed on Open. ---> System.InvalidOperationException: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.
分析
因已經作過兩輪評審,開發組此次提供了全面的資料,經過代碼評審發現邏輯中有使用LDAP(Windows活動目錄輕量目錄訪問協議Light Directory Access Protocol)遍歷登錄者全部活動目錄下的組。
此邏輯可能會產生請求ADFS查詢的瓶頸,阻塞請求。
同時發現部分被查詢的表中沒有建立索引(這個是在最初問過開發團隊但獲得的回答是確定的)並進行索引優化,另外,API採用.NET Entity Framework編寫,由SQL查詢監控看出因無索引致使EF生成相同表的嵌套(笛卡爾積)查詢,是致使表遍歷和產生表鎖的主要緣由。
對於大量出現的5xx錯誤,因上次性能測試沒有,主要針對修改的代碼進行評審發現增長了EF查詢邏輯,這也是致使循環嵌套的緣由。
結論
表索引優化是主要解決辦法。EF查詢最終改成明文查詢並SQL查詢優化。
總結
性能問題首先由測試入手,根據測試報告發現錯誤和性能瓶頸,主要以解決錯誤消除瓶頸爲主要原則。對於有數據庫存在的情景,注意查詢和索引優化,保證鏈接池有效支持應用併發。問題調研期間要了解總體架構(本次API嵌套問題和LDAP的使用都是後期由開發組告知)和所使用的技術,才能給出全面建議。從開發組角度應該訓練發現性能問題的敏感度。全部問題的發現和解決以測試事實數聽說話,不會存在莫須有的性能問題,全部問題皆有因緣。