效能測試遭遇TPS抖動問題
目前效能測試組正在對獨立秒殺進行效能壓測,效能抖動特別厲害。
由於獨立秒殺的介面大多數是經過volicity渲染過的頁面和資料的整合,所以在壓測的時候有很多volicity的錯誤。初步判定,感覺是volicity的效能問題才導致的。但是通過排查volicity發現,此版本沒有網傳的效能問題,而且程式碼層面上也沒見到有過多的效能問題點。
之後通過檢視jvm的堆內記憶體才發現,老年代的記憶體無法釋放,總是會經過很長一段時間,大概三十四分鐘後才會釋放。感覺很奇怪:
從上圖可以看到,堆內記憶體漲上去後,基本上就下不來了, 這些沒釋放的記憶體,基本上都在老年代。初步判定為jvm堆內記憶體要麼有大物件,要麼什麼東西一直持有,並未釋放。
之後從伺服器上dump資料下來,然後通過mat載入後,得到的分析如下:
可以看到,系統中,有一個ConcurrentHashMap的容器裡面,貌似對每個http請求,都做了一次快取。考慮到目前做的是壓測,那麼也就是說瞬間湧入千萬級別的請求也不為過,ConcurrentHashMap的體積在很短的時間就會暴漲,勢必會帶來頻繁的gc問題。如果只是儲存http請求狀態,為什麼http請求完畢,不會釋放呢?
帶著疑問去應用裡面進行排查,發現應用裡面根本沒有直接使用ConcurrentHashmap物件。那麼也就是說ConcurrentHashmap物件也許是存在什麼jar包裡面了。經過排查jar包,也沒發現什麼地方使用concurrenthashmap,頓時陷入了死局。
後來,壓測組發來一篇文章:壓力測試中JVM記憶體暴漲原因分析實戰, 看完文章,和我的遭遇非常一致,聯想到目前壓測直接使用ip+埠壓測,直接打到tomcat上進行壓測,而且介面返回資料都是經過velocity渲染的模板和資料組合,是有前端頁面的。所以說,按照文章中的說法,應該是tomcat對每一個進來的請求都會將狀態會話保持放到ConcurrentHashmap中導致的,而且這個狀態會話保持預設30分鐘後過期,這也是為啥GC一直下不來的原因了。
為了印證此說法,按照此文的建議, Memory Fully utilized by Java ConcurrentHashMap (under Tomcat)
<session-config>
<session-timeout>1</session-timeout>
</session-config>
之後修改程式碼,上預發,然後讓壓力機單壓預發這臺機器,可以看到堆記憶體回收如下:
可以看到當堆記憶體打到極高點後,jvm很快進行了一次回收,而且此次回收比較徹底。
驗證完畢,看來是這個原因。希望對你有幫助。