記一次接口壓力測試與性能調優

〇、經驗總結

1.若是總的CPU佔用率偏高,且基本都被業務線程佔用時,CPU佔用率太高的緣由跟JVM參數大小沒有直接關係,而跟具體的業務邏輯有關。
2.當設置JVM堆內存偏小時,GC頻繁會致使業務線程停頓增多,TPS降低,最後CPU佔用率也低了;
3.當設置JVM堆內存偏大時,GC次數降低,TPS上升,CPU佔用率馬上上升。
4.Dom4J 這個xml解析工具性能很強大,但在處理節點和層級都較多的xml文本時,總體解析效率依然會成爲業務處理瓶頸。java

1、背景說明

最近新項目上線,須要對項目中的一個HTTP接口進行壓力測試,以保證接口性能穩定性。該接口涉及到的主要業務是接收HTTP請求,獲取請求中的xml報文參數,並將xml報文解析後存入MySQL數據庫。接口業務流程以下:
記一次接口壓力測試與性能調優算法

該業務接口部署的服務器配置和部署MySQL組件的服務器配置一致,都是4核8G,50G普通硬盤,而且處於同一個內網網段,咱們預估的性能指標要達到200併發,500TPS。
在壓力測試過程當中,咱們重點關注TPS、GC次數、CPU佔用率和接口響應時間等指標。數據庫

2、測試過程

完成項目部署後,咱們開始編輯jemeter測試腳本,設置壓力測試的標準爲200個併發線程,在10秒內所有啓動,持續壓測時間15分鐘,接着開始啓動jemeter腳本進行測試。服務器

一、第一次壓力測試

(1)JVM配置

垃圾收集策略包括:老年代啓用CMS垃圾收集算法,新生代啓用ParNew垃圾收集算法,新生代最大存活週期爲15次minorGC,FullGC時使用CMS算法,並開啓CMS中的並行標記。
JVM內存分配:最大/最小堆內存爲512MB,Eden和Survivor比例爲8:2,永久代初始化64MB,最大128MB。
JVM配置參數以下:
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:MaxTenuringThreshold=15 -XX:+ExplicitGCInvokesConcurrent
-XX:+CMSParallelRemarkEnabled -Xms512m -Xmx512m -XX:SurvivorRatio=8 -XX:PermSize=64m -XX:MaxPermSize=128m併發

(2)性能指標監控

top命令觀察java線程的CPU佔用率(us表示用戶進程,sy表示系統進程):
記一次接口壓力測試與性能調優dom

jemeter工具輸出的TPS和接口響應時間:
記一次接口壓力測試與性能調優ide

jstat -gcutil {pid} {period_time} 輸出GC狀況
記一次接口壓力測試與性能調優工具

咱們根據上述指標監控的狀況能夠看出,目前CPU佔用率很高,每一個CPU上的業務線程都佔用了90%以上的CPU時間,年輕代GC次數頻繁,平均每秒鐘有8次左右,但TPS目前只有400左右。
一開始看到這個狀況,咱們覺得是JVM堆內存分配的不足,致使GC頻繁,從而引發CPU的高佔用率。因此咱們調大了堆內存參數,並進行第二次壓力測試。性能

二、第二次壓力測試

(1)JVM配置

JVM內存分配:最大/最小堆內存爲2048MB,Eden和Survivor比例爲8:2,永久代初始化512MB,最大512MB。
JVM配置參數以下:
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:MaxTenuringThreshold=15 -XX:+ExplicitGCInvokesConcurrent
-XX:+CMSParallelRemarkEnabled -Xmx2048m -Xms2048m -Xmn1024m -XX:NewSize=640m -XX:MaxNewSize=640m
-XX:SurvivorRatio=8 -XX:PermSize=512m -XX:MaxPermSize=512m測試

(2)性能指標監控

top命令觀察java線程的CPU佔用率(us表示用戶進程,sy表示系統進程):
記一次接口壓力測試與性能調優

jemeter工具輸出的TPS和接口響應時間:
記一次接口壓力測試與性能調優

jstat -gcutil {pid} {period_time} 輸出GC狀況:
記一次接口壓力測試與性能調優

根據上述指標監控的狀況能夠看出,此次JVM參數調整後,隨着堆內存擴大,年輕代GC次數下降了,平均每秒有2次左右,TPS提升到600左右。可是CPU佔用率依然很高,且都爲業務進程佔用。
從這個性能結果來看,堆內存的增大,能夠下降GC頻率,提升TPS。但CPU佔用率幾乎沒有變化,可能的緣由預計有兩個:
第1、業務邏輯中存在耗CPU的計算操做;
第2、業務代碼存在鎖,致使大量線程在等待鎖。
根據這個猜想,咱們決定打印出JVM線程快照,看下可否找到線程等待鎖的相關信息。
jstack -l {pid} > /log_dir/stack_log.txt 命令輸出線程快照信息到指定的目錄文件。
在線程快照文件裏查找狀態爲BLOCKED的線程記錄,發現出現較多BLOCKED狀態的線程是:
記一次接口壓力測試與性能調優

從線程快照來看,大量xml解析線程處於BLOCKED狀態,xml解析的業務處於阻塞狀態,下降了接口處理效率。

接着咱們把接口代碼中其餘邏輯代碼屏蔽,只留下xml解析代碼,發現CPU佔用率依然在90%以上,而一旦把xml解析代碼屏蔽,留下其餘業務代碼,CPU佔用率立刻下降到了70%,TPS上升,GC次數降低並保持穩定。

從上面這些處理的結果來看,CPU佔用率太高的緣由跟JVM參數大小沒有直接關係,而跟xml參數解析有關,由於xml參數報文包含十幾個節點,層級也較多,解析後生成的都是比較複雜的大對象。當設置JVM堆內存偏小時,GC頻繁會致使業務線程停頓,TPS降低,最後CPU佔用率也低了;當設置JVM堆內存偏大時,GC次數降低,TPS上升,CPU佔用率馬上升高到95%以上。因爲咱們對xml參數解析使用的是dom4j的方法,因此沒辦法在xml解析上面進行優化,只能在JVM參數和併發數上進行處理。最終爲了平衡CPU佔用率、TPS、GC三個方面的指標,考慮業務實際場景,咱們設置JVM堆內存爲1.5G,限制TPS爲200。

相關文章
相關標籤/搜索