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

適用對象和範圍

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

性能分析

  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模式,自動遞增/手工調速的組合進行流量控制。
    • 必須保證調優後的程序運行正確。
    • 系統的性能更大程度上取決於良好的設計,調優技巧只是一個輔助手段。
    • 調優過程是迭代漸進的過程,每一次調優的結果都要反饋到後續的代碼開發中去。
    • 性能調優不能以犧牲代碼的可讀性和可維護性為代價。