效能測試之測試分析與調優

EdisonYao發表於2021-11-12

適用物件和範圍

  適用於需要進行效能分析及調優的工作。 預期讀者為測試管理人員、測試實施人員、技術支援人員、專案質量管理人員、專案管理人員等系統技術質量相關人員。

效能分析

  1. 前提

    效能分析的前提除了需要豐富的效能測試監控(如PTS自身的客戶側監控、基礎類監控-阿里雲監控、應用類監控-ARMS監控等),還需要具備相關的技術知識(包括但不限於:作業系統、中介軟體、資料庫、開發等)。

  2. 流程
    • 很多情況下壓測流量並沒有完全進入到後端(服務端),在網路接入層(雲化的架構,例如:SLB/WAF/高防IP,甚至是CDN/全站加速等)可能就會出現由於各種規格(頻寬、最大連線數、新建連線數等)限制或者因為壓測的某些特徵符合CC和DDoS的行為而觸發了防護策略導致壓測結果達不到預期。
    • 接著看關鍵指標是否滿足要求,如果不滿足,需要確定是哪個地方有問題,一般情況下,伺服器端問題可能性比較大,也有可能是客戶端問題(這種情況非常小)。
    • 對於伺服器端問題,需要定位的是硬體相關指標,例如CPU,Memory,Disk I/O,Network I/O,如果是某個硬體指標有問題,需要深入的進行分析。
    • 如果硬體指標都沒有問題,需要檢視中介軟體相關指標,例如:執行緒池、連線池、GC等,如果是這些指標問題,需要深入的分析。
    • 如果中介軟體相關指標沒問題,需要檢視資料庫相關指標,例如:慢查SQL、命中率、鎖、引數設定。
    • 如果以上指標都正常,應用程式的演算法、緩衝、快取、同步或非同步可能有問題,需要具體深入的分析。

    具體如下圖所示:

    流程圖
  3. 可能瓶頸點
    • 硬體、規格上的瓶頸

      一般指的是CPU、記憶體、磁碟I/O方面的問題,分為伺服器硬體瓶頸、網路瓶頸(對區域網可以不考慮)。

    • 中介軟體上的效能瓶頸

      一般指的是應用伺服器、web伺服器等應用軟體,還包括資料庫系統。 例如:中介軟體weblogic平臺上配置的JDBC連線池的引數設定不合理,造成的瓶頸。

    • 應用程式上的效能瓶頸

      一般指的是開發人員開發出來的應用程式。 例如,JVM引數不合理,容器配置不合理,慢SQL(可使用阿里雲APM類產品如ARMS協助定位),資料庫設計不合理,程式架構規劃不合理,程式本身設計有問題(序列處理、請求的處理執行緒不夠、無緩衝、無快取、生產者和消費者不協調等),造成系統在大量使用者訪問時效能低下而造成的瓶頸。

    • 作業系統上的效能瓶頸

      一般指的是windows、UNIX、Linux等作業系統。 例如,在進行效能測試,出現實體記憶體不足時,虛擬記憶體設定也不合理,虛擬記憶體的交換效率就會大大降低,從而導致行為的響應時間大大增加,這時認為作業系統上出現效能瓶頸。

    • 網路裝置上的效能瓶頸

      一般指的是防火牆、動態負載均衡器、交換機等裝置。當前更多的雲化服務架構使用的網路接入產品:包括但不限於SLB、WAF、高防IP、CDN、全站加速等等。 例如,在動態負載均衡器上設定了動態分發負載的機制,當發現某個應用伺服器上的硬體資源已經到達極限時,動態負載均衡器將後續的交易請求傳送到其他負載較輕的應用伺服器上。在測試時發現,動態負載均衡器沒有起到相應的作用,這時可以認為網路瓶頸。

  4. 方法
    • CPU

      CPU資源利用率很高的話,需要看CPU消耗User、Sys、Wait哪種狀態。

      • 如果CPU User非常高,需要檢視消耗在哪個程式,可以用top(linux)命令看出,接著用top –H –p <pid>看哪個執行緒消耗資源高。如果是Java應用,就可以用jstack看出此執行緒正在執行的堆疊,看資源消耗在哪個方法上,檢視原始碼就知道問題所在;如果是c++應用,可以用gprof效能工具進行分析。
      • 如果CPU Sys非常高,可以用strace(linux)看系統呼叫的資源消耗及時間。
      • 如果CPU Wait非常高,考慮磁碟讀寫了,可以通過減少日誌輸出、非同步或換速度快的硬碟。
    • Memory

      作業系統為了最大化利用記憶體,一般都設定大量的cache,因此,記憶體利用率高達99%並不是問題,記憶體的問題主要看某個程式佔用的記憶體是否非常大以及是否有大量的swap(虛擬記憶體交換)。

    • 磁碟I/O

      磁碟I/O一個最顯著的指標是繁忙率,可以通過減少日誌輸出、非同步或換速度快的硬碟來降低繁忙率。

    • 網路I/O

      網路I/O主要考慮傳輸內容大小,不能超過硬體網路傳輸的最大值70%,可以通過壓縮減少內容大小、在本地設定快取以及分多次傳輸等操作提高網路I/O效能。

    • 核心引數

      核心引數一般都有預設值,這些核心引數預設值對於一般系統沒問題,但是對於壓力測試來說,可能執行的引數將會超過核心引數,導致系統出現問題,可以用sysctl來檢視及修改。

    • JVM

      JVM主要分析GC/FULL GC是否頻繁,以及垃圾回收的時間,可以用jstat命令來檢視,對於每個代大小以及GC頻繁,通過jmap將記憶體轉儲,再借助工具HeapAnalyzer來分析哪地方佔用的記憶體較高以及是否有記憶體洩漏可能。簡單點可以使用APM工具,例如阿里雲ARMS。

    • 執行緒池

      如果執行緒不夠用,可以通過引數調整,增加執行緒;對於執行緒池中的執行緒設定比較大的情況,還是不夠用可能的原因是:某個執行緒被阻塞來不及釋放,可能在等鎖、方法耗時較長、資料庫等待時間很長等原因導致,需要進一步分析才能定位。

    • JDBC連線池

      連線池不夠用的情況下,可以通過引數進行調整增加;但是對於資料庫本身處理很慢的情況下,調整沒有多大的效果,需要檢視資料庫方面以及因程式碼導致連線未釋放的原因。

    • SQL

      SQL效率低下也是導致效能差的一個非常重要的原因,可以通過檢視執行計劃看SQL慢在哪裡,一般情況,SQL效率低下原因主要有:

      類別子類表示式或描述原因
      索引 未建索引 產生全表掃描
      未利用索引 substring(card_no,1,4)=′5378′ 產生全表掃描
      amount/30< 1000 產生全表掃描
      convert(char(10),date,112)=′19991201′ 產生全表掃描
      where salary<>3000 產生全表掃描
      name like '%張' 產生全表掃描
      first_name + last_name ='beill cliton' 產生全表掃描
      id_no in(′0′,′1′) 產生全表掃描
      select id from t where num=@num 有引數也會產生全表掃描
      使用效能低的索引 oder by非聚族索引 索引效能低
      username='張三'and age>20 字串索引低於整形索引
      表中列與空NULL值 索引效能低
      儘量不要使用IS NULL或IS NOT NULL 索引效能低
      資料量 所有資料量 select * 很多列產生大量資料
      select id,name 表中有幾百萬行,產生大量資料
      巢狀查詢 先不過濾資料,後過濾資料 產生大量無用的資料
      關聯查詢 多表進行關聯查詢,先過濾掉小部分資料,在過濾大部分資料 大量關聯操作
      大資料量插入 一次次插入 產生大量日誌,消耗資源
      鎖等待 update account set banlance=100 where id=10 產生表級鎖,將會鎖住整個表
      死鎖 A:update a;update b;B:update b;update a; 將會產生死鎖
      遊標 Cursor Open cursor,fetch;close cursor 效能很低
      臨時表 create tmp table建立臨時表 產生大量日誌
      drop table 刪除臨時表 需要顯示刪除,避免系統表長時間鎖定
      其他 exist代替IN select num from a where num in(select num from b) in會逐個判斷,exist有一條就結束
      exist代替select count(*) 判斷記錄是否存在 count(*) 將累加計算,exist有就結束
      between代替IN ID in(1,2,3) IN逐個判斷,between是範圍判斷
      left outer join代替Not IN select ID from a where ID not in(select b.Mainid from b) NOT IN逐個判斷,效率非常低
      union all代替union select ID from a union select id from b union 刪除重複的行,可能會在磁碟進行排序而union all只是簡單的將結果並在一起
      常用SQL儘量用繫結變數方法 insert into A(ID) values(1) 直接寫SQL每次都要編譯,用繫結變數的方法只編譯一次,下次就可以用了

調優

  1. 調優步驟
    • 確定問題
      • 應用程式程式碼:在通常情況下,很多程式的效能問題都是寫出來的,因此對於發現瓶頸的模組,應該首先檢查一下程式碼。
      • 資料庫配置:經常引起整個系統執行緩慢,一些諸如大型資料庫都是需要DBA進行正確的引數調整才能投產的。
      • 作業系統配置:不合理就可能引起系統瓶頸。
      • 硬體設定:硬碟速度、記憶體大小等都是容易引起瓶頸的原因,因此這些都是分析的重點。
      • 網路:網路負載過重導致網路衝突和網路延遲。
    • 分析問題
      • 當確定了問題之後,我們要明確這個問題影響的是響應時間吞吐量,還是其他問題?
      • 是多數使用者還是少數使用者遇到了問題?如果是少數使用者,這幾個使用者與其它使用者的操作有什麼不同?
      • 系統資源監控的結果是否正常?CPU的使用是否到達極限?I/O情況如何?
      • 問題是否集中在某一類模組中?
      • 是客戶端還是伺服器出現問題? 系統硬體配置是否夠用?
      • 實際負載是否超過了系統的負載能力? 是否未對系統進行優化?

      通過這些分析及一些與系統相關的問題,可以對系統瓶頸有更深入的瞭解,進而分析出真正的原因。

    • 確定調整目標和解決方案

      高系統吞吐量,縮短響應時間,更好地支援併發。

    • 測試解決方案

      對通過解決方案調優後的系統進行基準測試。(基準測試是指通過設計科學的測試方法、測試工具和測試系統,實現對一類測試物件的某項效能指標進行定量的和可對比的測試)。

    • 分析調優結果

      系統調優是否達到或者超出了預定目標;系統是整體效能得到了改善,還是以系統某部分效能來解決其他問題;調優是否可以結束了。 最後,如果達到了預期目標,調優工作可以先告一段落。

  2. 調優注意事項
    • 在應用系統的設計開發過程中,應始終把效能放在考慮的範圍內,將效能測試常態化,日常化的內網的效能測試+定期的真實環境的業務效能測試,PTS都可以支援。
    • 確定清晰明確的效能目標是關鍵,進而將目標轉化為PTS中的壓測場景並設定好需要的目標量級,然後視情況選擇併發、TPS模式,自動遞增/手工調速的組合進行流量控制。
    • 必須保證調優後的程式執行正確。
    • 系統的效能更大程度上取決於良好的設計,調優技巧只是一個輔助手段。
    • 調優過程是迭代漸進的過程,每一次調優的結果都要反饋到後續的程式碼開發中去。
    • 效能調優不能以犧牲程式碼的可讀性和可維護性為代價。

相關文章