先說結論:通過優化Xms,改為和Xmx一致,使系統的超時率降了四分之三 ![image.png](https://img2023.cnblogs.com/blog/2058002/202306/2058002-20230628185820689-1353266318.png) # 1. 背景 一個同 ...
先說結論:通過優化Xms,改為和Xmx一致,使系統的超時率降了四分之三
1. 背景
一個同事說他負責的服務在一次上線之後超時率增加了一倍
2. 分析
2.1 機器的監控
首先找了一臺機器,看了監控
上線後最明顯的變化就是CPU使用率變高了
2.2 上線改動點
上線只加了簡單的判斷條件,按理不應該導致CPU變高成這樣
2.3 CPU使用率隨時間變低
又發現了一個奇怪的現象是,在沒有上線的情況下,CPU使用率突然降低了,然後就一直保持著很低的狀態
CPU降低之後,超時率也有所降低,現在大概能理解超時是和CPU使用率有關的,可能存在CPU瓶頸
2.4 依賴的服務
既然在沒有上線的情況下,CPU使用率會降低,肯定有什麼因素影響,猜測可能是依賴的服務,但依賴的服務太多,也沒辦法一個一個去看,哪個調用有問題
2.5 CPU和上線的關係
於是還是想在CPU使用率上找找問題,因為是上線導致的CPU使用率變高,所以看了其他上線時間的CPU使用率
還是有點思路了,發現大部分上線之後CPU使用率是會變高,部分沒有(後面知道,因為有的上線本身就是優化,所以CPU使用率也會變低)
2.6 CPU和記憶體的關係
之前一直在關心CPU,突然看見了記憶體的使用率,一下就明白的問題所在,從下麵這張圖可以看出,CPU使用率和記憶體使用率是成反比的
使用Java的都應該清楚,記憶體不夠的時候,就會STW,然後去啟動GC線程去GC,而且一般情況GC線程數和CPU核數是一致的,這個服務也是如此,此時CPU使用率必然是會變高的
上面3月6號CPU突然下降的原因也是因為記憶體使用變高了,這是在沒有上線的情況下
2.7 記憶體和JVM參數
可以看到上面的圖中,CPU使用率高的時候,記憶體占用只有20%左右,為什麼空這這麼多記憶體不用呢?看下JVM參數
-Xmx16g -Xms4g -Xss1024K -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=10 -XX:MetaspaceSize=512m -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:ParallelGCThreads=8 -XX:ConcGCThreads=8 -XX:G1HeapRegionSize=16m -XX:-OmitStackTraceInFastThrow
Xms配的是4G,也就是說JVM在啟動時只會申請4G記憶體,當記憶體不足時,先會GC,當GC釋放的記憶體還不夠時,才會去申請更大的記憶體
這樣的策略一般是為了節省記憶體,但目前主流的都是容器,節省下來的記憶體也不會給別的服務利用,所以我們這可以直接把Xms改為16G
改完之後立即得到了很好的效果,超時率降了四分之三,不過後續因為記憶體使用率變高,超過了閾值,所以又把Xmx和Xms調整為14G,這個問題可以參考我之前的文章一次Java服務記憶體過高的分析過程
3. 總結
- Xms配置過小,JVM啟動時記憶體不足導致GC線程占用過多CPU
- CPU不足時,超時率增加,CPU充足時,超時率降低
- Xms配置和Xmx一樣,超時率降低
4. Xms和Xmx
這兩個參數使用Java的都比較瞭解
Xmx: JVM的最大堆記憶體
Xms: JVM的初始堆記憶體
4.2 不一致的壞處
- 堆記憶體不夠時更頻繁的觸發GC
- 當GC完之後記憶體也不夠時,向系統申請記憶體,會花費更多的時間
4.2 改為一致的好處
為了避免在生產環境由於heap記憶體擴大或縮小導致應用停頓,降低延遲,同時避免每次垃圾回收完成後JVM重新分配記憶體。所以,-Xmx和-Xms一般都是設置相等的
在生產環境中把Xms和Xmx設為相同值也是Oracle官方推薦
5. 感想
這個配置從機器上線跑了兩年一直如此,大部分時間性能沒被充分利用,現在有二十臺機器都是以這樣一種低性能模式跑了這麼久,這絕對是一種浪費
在第三篇參考文章中,有個人的評論正好和我相反,他認為一開始將Xms和Xmx設置為一樣,而實際沒用那麼多,其實也是一種浪費,不過這是18年前的文章,那時容器沒有興起,服務都在一個物理機上面共用記憶體,會是有這種問題的
在容器中,節省的記憶體別的服務也利用不了,所以Xms最後設置和Xmx一致,但是容器也是可能造成浪費的,比如上面我把Xmx和Xms從16G改為14G,從監控上來看耗時和超時率下降了一點,也就是把這個容器的記憶體往下調一點也是可以接受的,具體調到多少合適也不太確定
不過這種優化很沒有必要,記憶體是很便宜的,而且適量冗餘一些性能也可以理解
既然這麼多好處,為什麼Oracle不預設把Xms和Xmx設置為一致呢,我覺得可能是目前還是有大部分Java應用都不是容器環境,全局考慮,沒有這樣做,或許後續Java會判斷是否是容器環境來自動設置Xms
參考
[2] Is there any advantage in setting Xms and Xmx to the same value?
[3] large difference between -Xms and -Xmx values in jvm
本文來自博客園,作者:songtianer,轉載請註明原文鏈接:https://www.cnblogs.com/songjiyang/p/17512319.html