2013年雙11過程中,促銷開啓的第一分鐘內支付寶的交易總額就突破了一億元,短期內大量用戶涌入的狀況下,如何保證用戶的支付順暢,是對支付寶應用系統的一個極大的挑戰。java
支付寶的性能測試場景分爲性能基線測試,項目性能測試。linux
任意一筆交易過來,咱們都須要對交易進行風險掃描,對於有多是帳戶盜用的交易,咱們會把這筆支付直接拒絕掉,或者經過手機校驗碼等方式進行風險釋放。web
咱們有一個老的掃描平臺A,如今須要構建一個新的掃描平臺B,對A中關鍵技術進行升級,並增長額外的功能。掃描的策略是存儲在DB中的,須要經過發佈來更新到應用服務器的內存中。服務器
a. 需求挖掘網絡
1),查看業務方的顯性需求。業務方給到的需求爲平臺B的分析性能要優於平臺A的性能。除此以外無其它的需求。數據結構
2),挖掘隱性需求.瞭解業務架構,瞭解業務流程。爲了保證掃描的性能,大量的存儲類的需求被設計爲異步處理,可是結果類的掃描須要使用到前面落地的數據,那麼在系統正常運行時是否會存在落地數據讀取不到的問題,在存儲抖動時是否會致使後續的分析掃描所有失效?架構
首先咱們經過運維監控平臺拿到平臺A的分析性能,RT<130ms, TPS>35.
基於以上的需求挖掘,咱們確認的性能測試場景爲
b. 技術方案
1).評估咱們的系統架構,系統調到鏈路,定位可能存在問題的瓶頸點。
2).掌握詳細技術實現方案,瞭解具體技術方案可能存在的性能問題。
好比咱們是否使用到了腳本動態編譯,是Java腳本仍是groovy腳本。是否使用到了線程池等異步處理,系統冪等性是如何控制的,數據結構是如何存儲與讀取的,是決策樹仍是圖型結構。
3).瞭解系統環境的差別,好比服務器位數、CPU、內存的差別,JDK版本及位數的差別。
基於以上的技術方案,咱們確認了上述3個性能測試場景可能存在的性能問題
1. 掃描性能場景
技術方案爲掃描引擎drools2升級到了drools5.
性能關注點爲請求掃描RT,TPS是否知足咱們的需求;JVM Old區內存溢出,Old區內存泄露;GC 頻率太高。CPU使用率,load.
2. 發佈性能場景
技術方案爲規則DB撈取->規則加載->規則引擎切換->規則腳本編譯。
性能關注點爲CPU使用率,load。JVM Perm區內存溢出,Perm區內存泄露,GC 頻率太高。GC 暫停應用時間。
3. 掃描過程當中發佈性能場景。
性能關注點爲請求掃描RT,TPS。規則發佈耗時,CPU使用率,load, JVM GC頻率。
c. 性能測試方案制訂
基於以上的分析
1. 掃描性能場景
性能測試方案:
使用jmeter 腳本進行分佈式壓測,一臺master, 三臺slaver. 參數自動構建,使用高斯定時器模擬真實場景。
使用jmeter 收集分析性能數據,使用nmon收集服務器性能數據,使用jconsole收集JVM數據。
經過標準:
RT<130ms, TPS>35.
JVM old 區內無內存泄露,無內存溢出。GC時間間隔>30min,暫停應用時間<150ms.
CPU<70%, load < core*1.5。
2. 發佈性能場景
性能測試方案:
發佈時間間隔時間限制從1min調整爲3s, 更快的暴露問題。
使用單元測試類推送發佈消息。
服務器shell 腳本收集發佈模塊性能數據。
使用nmon收集服務器性能數據。
使用jconsole收集JVM數據。
經過標準:
JVM Perm 區內無內存泄露,無內存溢出。GC時間間隔>10min,暫停應用時間<200ms.
發佈時間<30S
CPU<70%, load < core*1.5。
3.掃描過程當中發佈性能場景
性能測試方案:
使用jmeter腳本進行分佈式壓測,同時提交發布請求進行發佈。
同時使用掃描性能場景和發佈性能場景收集數據功能。
經過標準:
RT < 掃描性能場景結果RT * 110%.
TPS > 掃描性能場景結果TPS * 90%.
發佈時間 < 40s。
d. 發現的問題
1. 掃描性能場景
AVG RT = 473ms, CMS GC = 90ms, 應用暫停時間 = 1s, 所以測試未經過。
問題定位:
dump內存,使用ibm memory analyzer 分析。
確認cms gc的緣由爲drools引擎的finalize方法。Finzlize方法不能正確的釋放對象的引用關係,致使引用關係一直存在,沒法釋放。
調優方案:
根據drools的升級文檔,升級drools引擎後解決此問題
2. 發佈性能場景
CMS GC 回收失敗,內存沒法被釋放,應用宕機。
問題定位:
GC回收比例爲默認值68%,OLD區內存1024M,那麼回收的臨界值爲1024*0.68=696.32M。系統的JVM內存佔用爲500M,掃描策略相關的內存爲120M,在切換的過程當中,依賴額外的120M,所以只有在可用內存大於740M時才能正常回收。
解決方案:
調整JVM參數,擴大GC回收比例。
後續技術方案改造,使用增量發佈解決此問題。
3. 掃描過程當中發佈性能場景
問題定位:
掃描平臺發佈流程,當首次請求進來時執行腳本動態編譯過程,因爲腳本較多,所以全部腳本的動態編譯時間較長,在此過程當中,進來的全部請求都會被hand住,形成大量超時
解決方案:
把腳本的動態編譯提早到首次請求調用進來以前,編譯經過後再切換掃描引擎,保證首次請求進來前一切準備就緒。
性能測試的執行須要具有如下幾個條件:施壓工具,測試環境以及對測試結果的收集工具。
咱們先來講說施壓工具,支付寶使用的主流施壓工具是開源工具Apache JMeter,支持不少類型的性能測試:
支付寶大部分接口是webservice接口,基於soap協議,且都是java開發,因此使用jmeter很是方便,即便jemter工具自己沒有自帶支持的協議,也能夠經過開發插件的方式支持。
測試環境包括被壓機和施壓機環境,須要進行硬件配置和軟件版本確認,保證系統乾淨,無其餘進程干擾,最好能提早監控半小時到1小時,確認系統各項指標都無異常。
另外除了被壓機和施壓機,有可能應用系統還依賴其餘的系統,因此咱們須要明確服務器的數量和架構,1是方便咱們分析壓力的流程,幫助後面定位和分析瓶頸,2是因爲咱們線下搭建的環境越接近線上,測試結果越準確。可是一般因爲測試資源緊張或者須要依賴外圍,例如銀行的環境,就會比較麻煩,一般咱們會選擇適當的進行環境mock。固然,Mock的時候儘可能和真實環境保持一致,舉個簡單的例子,若是支付寶端系統和銀行進行通訊,線上銀行的平均處理時間爲100ms,那麼若是咱們在線下性能測試時須要mock銀行的返回,須要加入100ms延遲,這樣才能比較接近真實的環境。
另外除了測試環境,還有依賴的測試數據也須要重點關注,數據須要關注總量和類型,例如支付寶作交易時,db中流水萬級和億級的性能確定是不同的;還有db是否分庫分表,須要保證數據分佈的均衡性。通常考慮到線下準備數據的時長,通常性能測試要求和線上的數據保持一個數量級。
測試結果收集主要包括如下幾個指標:
響應時間、tps、錯誤率、cpu、load、IO、系統內存、jvm(java虛擬內存)。
其中響應時間、tps和業務錯誤率經過jemter能夠收集。
Cpu、load、io和系統內存能夠經過nmon或linux自帶命令的方式來監控。
Jvm能夠經過jdk自帶的jconsole或者jvisualvm來監控。
整體來講,監控了這些指標,對系統的性能就有了掌握,一樣這樣指標也能夠反饋系統的瓶頸所在。
咱們在上面一章中拿到性能測試結果,這麼多數據,怎麼去分析系統的瓶頸在哪裏呢,通常是按照這樣的思路,先看業務指標:響應時間、業務錯誤率、和tps是否知足目標。
若是其中有一個有異常,能夠先排除施壓機和外圍依賴系統是否有瓶頸,若是沒有,關注網絡、db的性能和鏈接數,最後關注系統自己的指標:
先看下圖:是通常性能測試環境部署圖
1.
咱們在定位的時候,可按照標註中的一、二、3數字依次進行排查,先排查施壓機是否有瓶頸、接着看後端依賴系統、db、網絡等,最後看被壓機自己,例如響應時間逐漸變慢,通常來講是外圍依賴的系統出現的瓶頸致使總體響應變慢。下面針對應用系統自己作下詳細的分析,針對常見問題舉1~2個例子:
1. 應用系統負載分析:
服務器負載瓶頸常常表現爲,服務器受到的併發壓力比較低的狀況下,服務器的資源使用率比預期要高,甚至高不少。致使服務器處理能力嚴重降低,最終有可能致使服務器宕機。實際性能測試工做中,常常會用如下三類資源指標斷定是否存在服務器負載瓶頸:
通常cup的使用率應低於50%,若是太高有可能程序的算法耗費太多cpu,或者某些代碼塊進行不合理的佔用。Load值儘可能保持在cpuS+2 或者cpuS*2,其中cpu和load通常與併發數成正比(以下圖)
1) 當vmstat命令輸出的si和so值顯示爲非0值,則表示剩餘可支配的物理內存已經嚴重不足,須要經過與磁盤交換內容來保持系統的穩定;因爲磁盤處理的速度遠遠小於內存,此時就會出現嚴重的性能降低;si和so的值越大,表示性能瓶頸越嚴重。
2) 用工具監控內存的使用狀況,若是出現下圖的增加趨勢(used曲線呈線性增加),有可能系統內存佔滿的狀況:
若是出現內存佔用一直上升的趨勢,有可能系統一直在建立新的線程,舊的線程沒有銷燬;或者應用申請了堆外內存,一直沒有回收致使內存一直增加。
對於java應用來講,太高的GC頻率也會在很大程度上下降應用的性能。即便採用了併發收集的策略,GC產生的停頓時間積累起來也是不可忽略的,特別是出現cmsgc失敗,致使fullgc時的場景。下面舉幾個例子進行說明:
1. Cmsgc頻率太高,當在一段較短的時間區間內,cmsGC值超出預料的大,那麼說明該JAVA應用在處理對象的策略上存在着一些問題,即過多過快地建立了長壽命週期的對象,是須要改進的。或者old區大小分配或者回收比例設置得不合理,致使cms頻繁觸發,下面看一張gc監控圖(藍色線表明cmsgc)
由圖看出:cmsGC很是頻繁,後經分析是由於jvm參數-XX:CMSInitiatingOccupancyFraction設置爲15,比例過小致使cms比較頻繁,這樣能夠擴大cmsgc佔old區的比例,下降cms頻率注。
調優後的圖以下:
2. fullgc頻繁觸發
當採用cms併發回收算法,當cmsgc回收失敗時會致使fullgc:
由上圖能夠看出fullgc的耗時很是長,在6~7s左右,這樣會嚴重影響應用的響應時間。經分析是由於cms比例過大,回收頻率較慢致使,調優方式:調小cms的回比例,儘早觸發cmsgc,避免觸發fullgc。調優後回收狀況以下
能夠看出cmsgc時間縮短了不少,優化後能夠大大提升。從上面2個例子看出cms比例不是絕對的,須要根據應用的具體狀況來看,好比應用建立的對象存活週期長,且對象較大,能夠適當提升cms的回收比例。
3. 疑似內存泄露,先看下圖
分析:每次cmsgc沒有回收乾淨,old區呈上升趨勢,疑似內存泄露
最終有可能致使OOM,這種狀況就須要dump內存進行分析:
-XX:HeapDumpPath=/home/admin/logs -XX:ErrorFile=/home/admin/logs/hs_err_pid%p.log