1. 程式人生 > >應用效能問題解決實際案例

應用效能問題解決實際案例

某專案在上線前的APT(Application Performance Testing應用程式效能測試)過程中發現效能問題,效能測試結果影響是否上線,緊急求助外部專案組技術專家。

因分屬不同專案,只能通過專案組提供的資訊進行分析。

 

第一輪評審

現象

根據APT效能監控截圖,左圖為併發使用者數和CPU使用率,右圖為單獨的CPU使用率情況。APT測試情景為併發使用者數以5分鐘為週期進行增加,增加使用者數25人,在40分鐘後達到最終200併發使用者並保持1小時200使用者活動狀態。

很明顯看出使用者穩定後CPU使用率還在持續增長,懷疑有記憶體洩露問題。

 

 

分析

第一輪我們拿到的是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增長

測試結果(記憶體使用量)

  • HttpClient: 455MB
  • HttpWebRequest: 242MB

圖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的使用都是後期由開發組告知)和所使用的技術,才能給出全面建議。從開發組角度應該訓練發現效能問題的敏感度。所有問題的發現和解決以測試事實資料說話,不會存在莫須有的效能問題,所有問題皆有因