Jmeter性能測試-GC相關

https://www.cnblogs.com/danqiu/p/6009016.html

 

Jmeter性能測試-GC相關

1.GC相關

HotSpot虛擬機將其物理上劃分爲兩個–新生代(young generation)和老年代(old generation)。
新生代(Young generation): 絕大多數最新被建立的對象會被分配到這裏,因爲大部分對象在建立後會很快變得不可到達,因此不少對象被建立在新生代,而後消失。對象從這個區域消失的過程咱們稱之爲」minor GC「。html

老年代(Old generation): 對象沒有變得不可達,而且重新生代中存活下來,會被拷貝到這裏。其所佔用的空間要比新生代多。也正因爲其相對較大的空間,發生在老年代上的GC要比新生代少得多。對象從老年代中消失的過程,咱們稱之爲」major GC「(或者」full GC「)java

圖中的持久代( permanent generation )也被稱爲方法區method area)。他用來保存類常量以及字符串常量。所以,這個區域不是用來永久的存儲那些從老年代存活下來的對象。這個區域也可能發生GC。而且發生在這個區域上的GC事件也會被算爲major GC。redis

新生代是用來保存那些第一次被建立的對象,他能夠被分爲三個空間數據庫

  •  一個伊甸園空間(Eden 
  •  兩個倖存者空間(Survivor )
  • 絕大多數剛剛被建立的對象會存放在伊甸園空間。
  • 在伊甸園空間執行了第一次GC以後,存活的對象被移動到其中一個倖存者空間。
  •   此後,在伊甸園空間執行GC以後,存活的對象會被堆積在同一個倖存者空間。
  •  當一個倖存者空間飽和,還在存活的對象會被移動到另外一個倖存者空間。以後會清空已經飽和的那個倖存者空間。
  • 在以上的步驟中重複幾回依然存活的對象,就會被移動到老年代。

jstat 是HotSpot JVM提供的一個監控工具api

jstat –gc  $<pid$> 1000緩存

 

S0C       S1C       S0U    S1U      EC         EU          OC         OU         PC         PU         YGC     YGCT    FGC      FGCT     GCT服務器

3008.0   3072.0    0.0     1511.1   343360.0   46383.0     699072.0   283690.2   75392.0    41064.3    2540    18.454    4      1.133    19.588網絡

3008.0   3072.0    0.0     1511.1   343360.0   47530.9     699072.0   283690.2   75392.0    41064.3    2540    18.454    4      1.133    19.588併發

3008.0   3072.0    0.0     1511.1   343360.0   47793.0     699072.0   283690.2   75392.0    41064.3    2540    18.454    4      1.133    19.588eclipse

 

這些信息很重要,由於它們展現了GC處理到底花費了多少時間。

在這個例子中,YGC 是217而YGCT 是0.928,這樣在簡單的計算數據平均數後,你能夠知道每次新生代的GC大概須要4ms(0.004秒),而full GC的平均時間爲33ms。

可是,只看數據平均數常常沒法分析出真正的GC問題。這是主要是由於GC操做時間嚴重的誤差(換句話說,假如兩次full GC的時間是 67ms,那麼其中的一次full GC可能執行了10ms而另外一個可能執行了57ms。)爲了更好地檢測每次GC處理時間,最好使用 –verbosegc來替代數據平均數。

爲何須要優化GC

或者說的更確切一些,對於基於Java的服務,是否有必要優化GC應該說,對於全部的基於Java的服務,並不老是須要進行GC優化,但前提是所運行的基於Java的系統,包含了以下參數或行爲:

  • 已經經過 -Xms 和–Xmx 設置了內存大小
  • 包含了 -server 參數
  • 系統中沒有超時日誌等錯誤日誌

換句話說,若是你沒有設定內存的大小,而且系統充斥着大量的超時日誌時,你就須要在你的系統中進行GC優化了。

可是,你須要時刻銘記一條GC優化永遠是最後一項任務。

我爲GC優化概括了兩個目的:

  1. 一個是將轉移到老年代的對象數量降到最少
  2. 另外一個是減小Full GC的執行時間

 

將轉移到老年代的對象數量降到最少

按代的GC機制由Oracle JVM提供,不包括能夠在JDK7以及更高版本中使用的G1 GC。換句話說,對象被建立在伊甸園空間,然後轉化到倖存者空間,最終剩餘的對象被送到老年代。某些比較大的對象會在被建立在伊甸園空間後,直接轉移到老 年代空間。老年代空間上的GC處理會新生代花費更多的時間。所以,減小被移到老年代對象的數據能夠顯著地減小Full GC的頻率。減小被移到老年代空間的對象的數量,可能被誤解爲將對象留在新生代。可是,這是不可能的。取而代之,你能夠調整新生代空間的大小。

減小Full GC執行時間

Full GC的執行時間比Minor GC要長不少。所以,若是Full GC花費了太多的時間(超過1秒),一些鏈接的部分可能會發生超時錯誤。

  • 若是你試圖經過消減老年代空間來減小Full GC的執行時間,可能會致使OutOfMemoryError 或者 Full GC執行的次數會增長。
  • 與之相反,若是你試圖經過增長老年代空間來減小Full GC執行次數,執行時間會增長。

所以,你須要將老年代空間設定爲一個「合適」的值。

影響GC性能的參數

正如咱們在第二篇文章結尾提到的,不要幻想「某我的設定了GC參數後性能獲得極大的提升,咱們爲何不和他用同樣的參數?」,由於不一樣的Web服務所建立對象的大小和他們的生命週期都不盡相同。

簡單來講,若是一個任務的執行條件是A,B,C,D和E,一樣的任務執行條件換爲A和B,你會以爲哪一個更快?從通常人的直覺來看,在A和B條件下執行的任務會更快。

Java GC參數也是相同的道理,設定一些參數不但沒有提升GC執行速度,反而可能致使他更慢。GC優化的最基本原則是將不一樣的GC參數用於2臺或者多臺服務器,並進行對比,並將那些被證實提升了性能或者減小了GC執行時間的參數應用於服務器。請謹記這一點。

下面這個表格列出了GC參數中與內存大小相關的,能夠影響性能的參數。

1GC優化須要考慮的Java參數

定義

參數

描述

堆內存空間

-Xms

Heap area size when starting JVM

啓動JVM時的堆內存空間。

 

-Xmx

Maximum heap area size

堆內存最大限制

新生代空間

-XX:NewRatio

Ratio of New area and Old area

新生代和老年代的佔比

 

-XX:NewSize

New area size

新生代空間

 

-XX:SurvivorRatio

Ratio ofEdenarea and Survivor area

伊甸園空間和倖存者空間的佔比

我在進行GC優化時常用-Xms,-Xmx和-XX:NewRatio。-Xms和-Xmx是必須的。你如何設定NewRatio 會對GC性能產生十分顯著的影響。有些人可能會問如何設定Perm區域的大小?你能夠經過-XX:PermSize 和-XX:MaxPermSize參數來設定,

當OutOfMemoryError 錯誤發生而且是因爲Perm空間不足致使時,另外一個可能影響GC性能的參數是GC類型。下表列出了全部可選的GC類型(基於JDK6.0)

在分析監控結果後,決定是否進行GC優化

在檢查GC狀態的過程當中,你應該分析監控結果以便決定是否進行GC優化,若是分析結果代表執行GC的時間只有0.1-0.3秒,那你就不必浪費時間去進行GC優化。可是,若是GC的執行時間是1-3秒,或者超過10秒,GC將勢在必行。

可是,若是你已經爲Java分配了10GB的內存,而且不能再減小內存大小,你將沒法再對GC進行優化。在進行GC優化 以前,你必須想清楚你爲何要分配如此大的內存空間。假如當你分1 GB 或 2 GB內存時出現OutOfMemoryError ,你應該執行堆內存轉儲(heap dump),並消除隱患。

注意:

堆內存轉儲是一個用來檢查Java內存中的對象和數據的文件。該文件能夠經過執行JDK中的jmap命令來建立。在建立文件的過程當中,Java程序會暫停,所以不要再系統執行過程當中建立該文件。

若是GC執行時間知足下面全部的條件,就意味着無需進行GC優化了。

  • Minor GC執行的很快(小於50ms)
  • Minor GC執行的並不頻繁(大概10秒一次)
  • Full GC執行的很快(小於1s)
  • Full GC執行的並不頻繁(10分鐘一次)

上面提到的數字並非絕對的;他們根據服務狀態的不一樣而有所區別,某些服務可能知足於Full GC每次0.9秒的速度,但另外一些可能不是。所以,針對不一樣的服務設定不一樣的值以決定是否進行GC優化。

  • 設定內存空間大小

下表展現了內存空間大小,GC執行次數以及GC執行時間三者間的關係。

    • 大內存空間
      • 減少GC執行次數
      • 增長GC執行時間
    • 小內存空間
      • 減少GC執行時間
      • 增長GC執行次數

關於如何設置內存空間的大小,沒有惟一的標準答案。若是服務 器資源足夠,並且Full GC也可能在1秒內完成,設置爲10GB固然可行。。但絕大多數服務器並非這樣,當內存設爲10GB時,可能要花費10~30秒來執行Full GC。固然,執行時間會隨對象的大小而改變。

鑑於如此,咱們應該如何設定內存空間大小呢?一 般來講,我建議爲500MB。不過請注意這不是讓你將WAS的內存參數設置爲–Xms500m 和–Xmx500m。根據優化GC以前的狀態,若是 Full GC執行以後內存空間剩餘300MB,那麼最好將內存設置爲1GB(300MB(默認程序佔用)+ 500MB(老年代最小空間)+200MB(空閒內存))。也就是說你要爲老年代額外設置500MB。所以,若是你有三個執行服務器,內存分別設置爲 1GB,1.5GB,2GB,而且檢查結果。

理論上來說,GC執行速度應該遵循1GB> 1.5GB> 2GB,所以1GB執行GC速度最快。可是並不說明1GB空間的Full GC會花費1秒而2GB空間會花費2秒。時間取決於服務器的性能和對象的大小。所以,最佳的方式是創建儘量多的衡量指標來監控他們。

對於內存空間大小,你應該額外設定NewRatio參數。 NewRatio參數是新生代和老年代空間的比例,即XX:NewRatio=1意味着新生代與老年代之比爲1:1。對於1GB來講就是新生代和老年代各 500MB。若是NewRatio爲2,意味着新生代老年代之比爲1:2,所以該值越大,老年代空間越大,新生代空間越小。

這看似一件不是很重要的事情,但NewRatio參數會顯著地影響整個GC的性能。若是新生代空間很小,會用更多的對象被轉移到老年代空間,這樣致使頻繁的Full GC,增長暫停時間。

你能夠簡單的認爲NewRatio 爲1是最佳的選擇,可是,有時可能設置爲2或3更好,我就見過不少這樣的例子。

如何最快的完成GC優化?對比性能測試的結果 應該是最快地方法,爲每一臺服務器設置不一樣的參數並監控他們的狀態,強烈建議至少監控1或2天的數據。可是,當你對GC優化是,你要確保每次執行相同的負 載。而且請求的比率,例如URL都應該是一致的。不過,即使對於專業測試人員要想精確的控制負載也是很難的,並要花費大量的時間準備。所以,相對來講比較 方便和容易的方法是調整才參數,以後花費較長的時間收集結果。 

示例1

下面這個例子針對 Service S的優化,對於最近被部署的 Service S,Full GC花費了太長的時間。

請看 jstat –gcutil的執行結果。

 

1

2

S0 S1 E O P YGC YGCT FGC FGCT GCT

12.16 0.00 5.18 63.78 20.32 54 2.047 5 6.946 8.993

 

最左邊的Perm 空間對於最初的GC優化不是很重要,這一次YGC參數的值更加有用。

Minor GC和Full GC的平均值以下表所示

3Service SMinor GC Full GC的平均執行時間

GC 類型

GC 執行次數

GC 執行時間

平均

Minor GC

54

2.047

37 ms

Full GC

5

6.946

1,389 s

最重要的是下面兩個數據

  • 新生代實際使用空間: 212,992 KB
  • 老年代實際使用空間: 1,884,160 KB

所以,總的內存空間爲2GB,不算Perm空間的話,新生代與老年代之比爲1:9。經過jstat和-verbosegc 日誌進行數據收集,並把三臺服務器按照以下方式設置。

  • NewRatio=2
  • NewRatio=3
  • NewRatio=4

一天以後,檢查系統的GC日誌後發現,在設置了NewRatio參數後很幸運的沒有發生Full GC,

爲何?

  • NewRatio=2: 45 ms
  • NewRatio=3: 34 ms
  • NewRatio=4: 30 ms

咱們看到NewRatio=4 是最佳的參數,雖然它的新生代空間最小,但GC時間確最短。設定這個參數以後,系統沒有執行過Full GC。

爲了說明這個問題,下面是服務之星一段時間後執行jstat –gcutil的結果

 

1

2

S0 S1 E O P YGC YGCT FGC FGCT GCT

8.61 0.00 30.67 24.62 22.38 2424 30.219 0 0.000 30.219

 

你可能會認爲由於服務器接受的請求少才致使的GC執行頻率降低。實際上,雖然Full GC沒有執行,可是Minor GC被執行了 2,424次。

示例2

這是一個針對ServiceA的例子,咱們經過公司內部的應用性能管理系統(APM)發現JVM暫停了至關長的時間(超過8秒),所以咱們進行了GC優化。咱們找到了Full GC執行時間過長的緣由,並着手解決。

進行GC優化的第一步,就是咱們添加了-verbosegc參數,並獲得以下結果。

1:進行GC優化以前的STW時間

如上圖所示,由HPJMeter自動生成的圖片之一。X座標表示JVM執行的時間。Y座標表示每次GC的時間。CMS綠點,表示Full GC結果。Parallel Scavenge藍點,表示Minor GC結果。

以前我曾經說過CMS GC是最快的,可是上面的的結果顯示出於某種緣由,它最多花費了15秒。是什麼致使這個結果?是否想起我以前提過的,CMS在進行內存清理時,會變慢。與此同時,服務的內存被設定爲 –Xms1g和–Xmx4g ,且實際分配了4GB內存。

所以,我將GC類型從CMS改成Parallel GC。而且將內存改成2GB,設定NewRatio 爲3。幾小時以後我使用 jstat –gcutil獲得以下結果

 

1

2

S0 S1 E O P YGC YGCT FGC FGCT GCT

0.00 30.48 3.31 26.54 37.01 226 11.131 4 11.758 22.890

 

相對於4GB時的15秒,Full GC變成了平均每次3秒。可是3秒同樣比較慢,所以我設計了以下6種場景。

  • Case 1: -XX:+UseParallelGC -Xms1536m -Xmx1536m -XX:NewRatio=2
  • Case 2: -XX:+UseParallelGC -Xms1536m -Xmx1536m -XX:NewRatio=3
  • Case 3: -XX:+UseParallelGC -Xms1g -Xmx1g -XX:NewRatio=3
  • Case 4: -XX:+UseParallelOldGC -Xms1536m -Xmx1536m -XX:NewRatio=2
  • Case 5: -XX:+UseParallelOldGC -Xms1536m -Xmx1536m -XX:NewRatio=3
  • Case 6: -XX:+UseParallelOldGC -Xms1g -Xmx1g -XX:NewRatio=3

那一個最快呢?結果顯示,內存越小,結果越好。下圖展現了Case6的結果。這是GC的性能最好。最長的響應時間只有1.7秒。平均時間在1秒以內。

2Case6的時間圖表

基於以上結果。咱們按照Case6調整了GC參數。可是,這致使了天天晚上都會發生OutOfMemoryError。在這裏很難解釋具體的緣由。簡單來講,批處理程序致使了內存泄漏。相關的問題已經被解決。

若是對GC日誌只分析很短的時間就貿然對全部服務器進行優化是很是危險的。請時刻牢記,你必須同時分析GC日誌和應用程序。

咱們回顧了兩個關於GC優化的例子,正如我以前提到的,例子中提到的GC參數,能夠設置在相同的服務器之上,但前提是他們具備相同的CPU,操做系統,JDK版本以及運行着相同的服務。可是不要直接把我用過的參數用到你的服務至上,它們未必能很好的工做。

 

切實地調優

若是測試的結果知足了預期,那麼你不須要對程序進行性能調優。若是沒有達到預期結果,你就應該執行調優來解決問題。接下來會經過實例講解方法。

stop-the-world耗時過長

stop-the-world耗時過長多是因爲GC參數不合理或者代碼實現不正確。你能夠經過分析工具或堆內存轉儲文件(Heap dump)來定位問題,好比檢查堆內存中對象的類型和數量。若是在其中找到了不少沒必要要的對象,那麼最好去改進代碼。若是沒有發現建立對象的過程當中有特別 的問題,那麼最好單純地修改GC參數。

爲了適當地調整GC參數,你須要獲取一段足夠長時間的GC日誌,還必須知道哪些狀況會致使長時間的stop-the-world。想了解更多關於如何選擇合適的GC參數,能夠閱讀我同事的一篇博文:How to Monitor Java Garbage Collection

CPU使用率太低

當系統發生阻塞,吞吐量和CPU使用率都會下降。這多是因爲網絡系統或者併發的問題。爲了解決這個問題,你能夠分析線程轉儲信息(Thread dump)或者使用分析工具。閱讀這篇文章能夠得到更多關於線程轉儲分析的知識:How to Analyze Java Thread Dumps

你可使用商業的分析工具對線程鎖進行精確的分析,不過大部分時候,只需使用JVisualVM中的CPU分析器,就能得到足夠的信息。

CPU使用率太高

若是吞吐量很低可是CPU使用率卻很高,極可能是低效率代碼致使的。這種狀況下,你應該使用分析工具定位代碼中性能的瓶頸。可以使用的工具備:JVisualVMEclipse TPTP或者JProbe

調優方法

建議你使用以下方法對程序進行調優。

首先,檢查性能調優是否必要。測量性能不是一件簡單的工做,你也不能保證每次都得到滿意的結果。所以若是程序已經知足預期性能需求,沒必要在調優上增長額外的投入了。

問題只出在一個地方,你要作的就是去解決掉它。二八定律(Pareto principle)對性能調優一樣適用。這不是說某個模塊的低性能必定只源於一個問題,而是強調咱們應該在調優時把注意力放在影響最大的那個問題上。在處理好了最重要的以後,你才應該去解決剩下其餘的。也就是建議一次只對一個問題進行修復。

另外須要考慮到氣球效應(Balloon effect),有得必有失。你能夠經過使用緩存來提升響應能力,可是當緩存逐漸增大,執行一次Full GC的時間也會更長。通常而言,若是你但願內存使用率比較低,那麼吞吐量和響應能力可能都會惡化。所以,要知道什麼對本身程序來講最重要的,而哪些又是次要的。

到此爲止,你應該已經瞭解瞭如何對Java程序進行性能調優。爲了介紹性能測定的具體過程,我不得不省略其中一些細節,不過我認爲這些也足夠應對大多數Java Web服務端程序了

 

2.操做相關

1.如何考慮一個性能需求

1. 一般拿到一個性能需求,須要瞭解接口模型,整個接口的使用比例和容量,系統結構和技術方案,數據庫緩存和索引分佈,設計出合理的測試計劃,設計的原則是儘量真實的模擬線上狀況。

2.根據設計出的測試計劃,使用一個線程運行測試計劃,得出測試結果,對比測試指標

3.以線性增加的方式增長併發數,比較測試結果是否爲線性增加

4.測試結果平緩區一般表明着系統容量的最大區域,分析此時的測試結果,如 TPS和響應時間等

5.分析數據庫TPS、QPS等數據,redis命中率,MQ吞吐率,javaGC,程序佔用時間等各方面因素提升系統性能

6.經過jstack分析各模塊的資源佔用狀況。

7.優化後的程序要通過大批量數據測試確保測試程序不會發生錯誤

8.根據測試概要報告,數據庫監控數據等數據整合測試報告

9. 須要關注api層用的是長鏈接仍是短鏈接,長鏈接的話須要在jmeter裏勾選keep alive

2.如何保證jmeter自身性能

1.使用命令行啓動,減小界面形成的性能問題

2.命令行記錄聚合報告,不要啓動過多的其餘監控報告

3.儘量關閉沒必要要的日誌,包括測試代碼的log,jmeter自身日誌。

4.確保測試腳本計時準確,需確認好那些步驟須要計時,那些在準備在計時以外

5.過多的併發使用分佈式請求,當本地cpu,mem佔用比較大時,修改jmeter.properties,增長遠程remote-server,並啓動(具體操做見jmeter操做手冊)

3.如何分析測試結果

1.根據聚合報告分析90%,95%,和最大等指標,找出程序廣泛的響應時間。

2.讓開發人員查詢最大響應時間時的日誌,分析程序層面的執行任務狀況

3.使用jstack等分析當前程序的資源等待狀況,系統資源狀況

值得關注的線程狀態有:
     死鎖,Deadlock(重點關注)
     執行中,Runnable  
     等待資源,Waiting on condition(重點關注)
     等待獲取監視器,Waiting on monitor entry(重點關注)
     暫停,Suspended
     對象等待中,Object.wait() 或 TIMED_WAITING
     阻塞,Blocked(重點關注) 
     中止,Parked

示例圖

4.分析gc結果,cpu,IO等狀況,分析程序是否充分利用了系統資源

5.對比分析各併發數的程序響應狀況。

分類: 性能測試

相關文章
相關標籤/搜索