一次生產的 JVM 優化案例
點選上方“芋道原始碼”,選擇“設為星標”
做積極的人,而不是積極廢人!
原始碼精品專欄
來源:http://t.cn/EfQaVFi
背景
GC資料
GC日誌
分析與優化
背景
生產環境有二臺阿里雲伺服器,均為同一時期購買的,CPU、記憶體、硬碟等配置相同。具體配置如下:
節點 | CPU | 記憶體 | 硬碟 | 其它 |
---|---|---|---|---|
A | 2CPU | 4G | 普通雲盤 | Centos6.4 64位+JDK1.8.0_121 |
B | 2CPU | 4G | 普通雲盤 | Centos6.4 64位+JDK1.8.0_121 |
由於這二伺服器硬體和軟體配置相同,並且執行相同的程式,所以在Nginx輪詢策略均weight=1,即平臺的某個流量由這二臺機器平分。
有一次對系統進行例行檢查,使用PinPoint檢視下伺服器”Heap Usage”的使用情況時,發現,在有一個系統Full GC非常頻繁,大約五分鐘一次Full GC(如果不明白Full GC的什麼意思的,請自行百度),嚇我一跳。這麼頻繁的Full GC,導致系統暫停處理業務,對系統的實時可用性大打折扣。我檢查了一下Tomcat(Tomcat8.5.28)配置,發現在tomcat沒有作任何關於JVM記憶體的設定,全部使用預設模式。由於這二伺服器硬體和軟體配置相同,並且執行相同的程式,所以在Nginx輪詢策略均weight=1,即平臺的某個流量由這二臺機器平分。
GC資料
在業務峰期間,通過PinPoint觀察的A、B節點的”Heap Usage”使用情況,分別進行以下幾個時間段資料。
3小時圖:
上圖B系統在三個小時內,一共發生了22次Full GC,大約每8分鐘進行一次Full GC。每次Full GC的時間大概有150ms左右,即B系統在三個小時內,大約有3300ms暫停系統執行。從上圖來看,堆的空間最大值在890M左右,但在堆空間的大小大約200M就發生Full GC了,從系統資源的利用角度來考慮,這個使用率太低了。
上圖A系統在3個小時內,一共發生了0次Full GC,嗯,就是沒有任何停頓。 在這3小時,系統一直在處理業務,沒有停頓。堆的總空間大約1536m,目前堆的空間大於500M。
6小時圖:
上圖B系統在6個小時的資料統計和3個小時很像,6個小時內一共發生了N次Full GC,均是堆的空間小於200M就發生Full GC了。
上圖A系統在6個小時內,一共發生了0次Full GC,表現優秀。
12小時
上圖B系統在12個小時內,一共發生了N次Full GC,左邊Full GC比較少,是因為我們的業務主要集中白天,雖然晚上屬於非業務高峰期間,還是有Full GC。
上圖A系統在12個小時內,一共發生了0次Full GC,表現優秀。
GC日誌
看下gc.log檔案,因為我們兩臺伺服器都輸出了gc的詳細日誌,先看下B系統的Full GC日誌。
上圖全部是” [Full GC (Ergonomics)”日誌,是因為已經去掉” GC (Allocation Failure”日誌,這樣更方便觀察和分析日誌,選取GC日誌檔案最後一條Full GC日誌。
2018-12-24T15:52:11.402+0800: 447817.937: [Full GC (Ergonomics) [PSYoungGen: 480K->0K(20992K)] [ParOldGen: 89513K->69918K(89600K)] 89993K->69918K(110592K), [Metaspace: 50147K->50147K(1095680K)], 0.1519366 secs] [Times: user=0.21 sys=0.00, real=0.15 secs]
可以計算得到以下資訊:
堆的大小:110592K=108M
老生代大小:89600K=87.5M
新生代大小:20992K=20.5M
分析:這次Full GC是因為老年代物件佔用的空間的大小已經超過老年代容量 ([ParOldGen: 89513K->69918K(89600K)])引發的Full GC。是因為分配給老年代的空間太小,遠遠不能滿足系統對業務的需要,導致老年代的空間常常被佔滿,老年代的空間滿了,導致的Full GC。由於老年代的空間比較小,所以每次Full GC的時間也比較短。
A系統日誌,只有2次Full GC,這2次GC均發生在系統啟動時:
7.765: [Full GC (Metadata GC Threshold) [PSYoungGen: 18010K->0K(458752K)] [ParOldGen: 15142K->25311K(1048576K)] 33153K->25311K(1507328K), [Metaspace: 34084K->34084K(1081344K)], 0.0843090 secs] [Times: user=0.14 sys=0.00, real=0.08 secs]
可以得到以下資訊:
堆的大小:1507328K=1472M
老生代大小:89600K=1024M
新生代大小:20992K=448M
分析:A系統只有系統啟動才出現二次Full GC現象,而且是” Metadata GC Threshold”引起的,而不是堆空間引起的Full GC。雖然經過一個星期的觀察,A系統沒有Full GC,但一旦發生Full GC時間則會比較長。其它系統增加發現過,1024M的老年代,Full GC持續的時間大約是90ms秒。所以看得出來推也不是越大越好,或者說在UseParallelOldGC收集器中,堆的空間不是越大越好。
分析與優化
總體分析:
B系統的Full GC過於頻繁,是因為老生代只有約108M空間,根本無法滿足系統在高峰時期的記憶體空間需求。由於ParOldGen(老年代)常常被耗盡,所以就發生Full GC事件了。
A系統的堆初始空間(Xms)和堆的最大值(Xmx)均為1536m,完全可以滿足業務高峰期的記憶體需求。
優化策略:
B系統先增加堆空間大小,即通過設定Xms、 Xmx值增加堆空間。直接把Xms和Xmx均設定為1024M。直接堆的啟動空間(Xms)直接設定為堆的最大值的原因是:因為直接把Xms設定為最大值(Xmx)可以避免JVM執行時不停的進行申請記憶體,而是直接在系統啟動時就分配好了,從而提高系統的效率。把Xms(堆大小)設定為1024M,是因為採用JDK的建議,該建議通過命令得到” java -XX:+PrintCommandLineFlags -version” 。
其中,“-XX:MaxHeapSize=1004719104”,即Xmx為1024M,其它建議暫時不採納。所以綜合下來的B系統的JVM引數設定如下:export JAVA_OPTS="-server –Xms1024m -Xmx1024m -XX:+UseParallelOldGC -verbose:gc -Xloggc:../logs/gc.log -XX:+PrintGCDetails -XX:+PrintGCTimeStamps"
A系統JVM引數設定保持不變,以便觀察系統執行情況,即:export JAVA_OPTS="-server -Xms1536m -Xmx1536m -XX:+UseParallelOldGC -verbose:gc -Xloggc:../logs/gc.log -XX:+PrintGCDetails -XX:+PrintGCTimeStamps"
將A、B節點系統的JVM引數採用2套引數,是為了驗證A或B的引數更適合實際情況。
歡迎加入我的知識星球,一起探討架構,交流原始碼。加入方式,長按下方二維碼噢:
已在知識星球更新原始碼解析如下:
如果你喜歡這篇文章,喜歡,轉發。
生活很美好,明天見(。・ω・。)ノ♡
相關文章
- 一次生產 CPU 100% 排查優化實踐優化
- JVM效能優化 (一) 初識JVMJVM優化
- 一次生產事故的最佳化經歷
- Oracle效能優化-SQL優化(案例一)Oracle優化SQL
- JVM效能優化(一)JVM技術入門JVM優化
- 說一說 JVM 對鎖的優化JVM優化
- 【MySQL】NOT EXISTS優化的一個案例MySql優化
- MySQL SQL優化案例(一)MySql優化
- 一次生產 CPU 100% 排查最佳化實踐
- JVM鎖優化JVM優化
- jvm優化理解JVM優化
- JVM效能優化JVM優化
- 記一次生產慢sql索引最佳化及思考SQL索引
- JVM編譯優化JVM編譯優化
- 一次生產環境的docker MySQL故障DockerMySql
- 一次生產環境OOM排查OOM
- JVM 原理與優化 (1)JVM優化
- Oracle 某行系統SQL優化案例(一)OracleSQL優化
- Oracle優化案例-從Exadata遷移到國產一體機一般方法探究(四)Oracle優化
- Oracle效能優化-SQL優化(案例二)Oracle優化SQL
- Oracle效能優化-SQL優化(案例三)Oracle優化SQL
- Oracle效能優化-SQL優化(案例四)Oracle優化SQL
- 深入認識二進位制序列化--記一次生產事故的思考
- 深入理解JVM(③)Java的鎖優化JVMJava優化
- 一次生產環境CPU佔用高的排查
- 《java學習二》jvm效能優化-----認識jvmJavaJVM優化
- Oracle優化案例-使用with as優化Subquery Unnesting(七)Oracle優化
- SQL優化案例-使用with as優化Subquery Unnesting(七)SQL優化
- 記一次生產事故 磁碟被佔滿
- JVM調優引數、方法、工具以及案例總結JVM
- 《java學習三》jvm效能優化-------調優JavaJVM優化
- Oracle優化案例-單表分頁語句的優化(八)Oracle優化
- SQL優化案例-單表分頁語句的優化(八)SQL優化
- SQL優化案例 - 從Exadata遷移到國產沃趣一體機一般方法探究(四)SQL優化
- SQL優化案例 | 從Exadata遷移到國產沃趣一體機一般方法探究(四)SQL優化
- SQL優化之多表關聯查詢-案例一SQL優化
- redis快取優化案例Redis快取優化
- Oracle優化案例-(三十四)Oracle優化