一次生产的 JVM 优化案例
背景
生產(chǎn)環(huán)境有二臺(tái)阿里云服務(wù)器,均為同一時(shí)期購(gòu)買(mǎi)的,CPU、內(nèi)存、硬盤(pán)等配置相同。具體配置如下:
| A | 2CPU | 4G | 普通云盤(pán) | Centos6.4 64位+JDK1.8.0_121 |
| B | 2CPU | 4G | 普通云盤(pán) | Centos6.4 64位+JDK1.8.0_121 |
由于這二服務(wù)器硬件和軟件配置相同,并且運(yùn)行相同的程序,所以在Nginx輪詢策略均weight=1,即平臺(tái)的某個(gè)流量由這二臺(tái)機(jī)器平分。
有一次對(duì)系統(tǒng)進(jìn)行例行檢查,使用PinPoint查看下服務(wù)器”Heap Usage”的使用情況時(shí),發(fā)現(xiàn),在有一個(gè)系統(tǒng)Full GC非常頻繁,大約五分鐘一次Full GC(如果不明白Full GC的什么意思的,請(qǐng)自行百度),嚇我一跳。這么頻繁的Full GC,導(dǎo)致系統(tǒng)暫停處理業(yè)務(wù),對(duì)系統(tǒng)的實(shí)時(shí)可用性大打折扣。我檢查了一下Tomcat(Tomcat8.5.28)配置,發(fā)現(xiàn)在tomcat沒(méi)有作任何關(guān)于JVM內(nèi)存的設(shè)置,全部使用默認(rèn)模式。
?
GC數(shù)據(jù)
在業(yè)務(wù)高峰期間,通過(guò)PinPoint觀察的A、B節(jié)點(diǎn)的”Heap Usage”使用情況,分別進(jìn)行以下幾個(gè)時(shí)間段數(shù)據(jù)。
3小時(shí)圖:
上圖B系統(tǒng)在三個(gè)小時(shí)內(nèi),一共發(fā)生了22次Full GC,大約每8分鐘進(jìn)行一次Full GC。每次Full GC的時(shí)間大概有150ms左右,即B系統(tǒng)在三個(gè)小時(shí)內(nèi),大約有3300ms暫停系統(tǒng)運(yùn)行。從上圖來(lái)看,堆的空間最大值在890M左右,但在堆空間的大小大約200M就發(fā)生Full GC了,從系統(tǒng)資源的利用角度來(lái)考慮,這個(gè)使用率太低了。
上圖A系統(tǒng)在3個(gè)小時(shí)內(nèi),一共發(fā)生了0次Full GC,嗯,就是沒(méi)有任何停頓。 在這3小時(shí),系統(tǒng)一直在處理業(yè)務(wù),沒(méi)有停頓。堆的總空間大約1536m,目前堆的空間大于500M。
6小時(shí)圖:
上圖B系統(tǒng)在6個(gè)小時(shí)的數(shù)據(jù)統(tǒng)計(jì)和3個(gè)小時(shí)很像,6個(gè)小時(shí)內(nèi)一共發(fā)生了N次Full GC,均是堆的空間小于200M就發(fā)生Full GC了。
上圖A系統(tǒng)在6個(gè)小時(shí)內(nèi),一共發(fā)生了0次Full GC,表現(xiàn)優(yōu)秀。
12小時(shí)
上圖B系統(tǒng)在12個(gè)小時(shí)內(nèi),一共發(fā)生了N次Full GC,左邊Full GC比較少,是因?yàn)槲覀兊臉I(yè)務(wù)主要集中白天,雖然晚上屬于非業(yè)務(wù)高峰期間,還是有Full GC。
上圖A系統(tǒng)在12個(gè)小時(shí)內(nèi),一共發(fā)生了0次Full GC,表現(xiàn)優(yōu)秀。
?
GC日志
看下gc.log文件,因?yàn)槲覀儍膳_(tái)服務(wù)器都輸出了gc的詳細(xì)日志,先看下B系統(tǒng)的Full GC日志。
上圖全部是” [Full GC (Ergonomics)”日志,是因?yàn)橐呀?jīng)去掉” 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]
可以計(jì)算得到以下信息:
堆的大小:110592K=108M
老年代大小:89600K=87.5M
新生代大小:20992K=20.5M
分析:這次Full GC是因?yàn)槔夏甏鷮?duì)象占用的空間的大小已經(jīng)超過(guò)老年代容量 ([ParOldGen: 89513K->69918K(89600K)])引發(fā)的Full GC。是因?yàn)榉峙浣o老年代的空間太小,遠(yuǎn)遠(yuǎn)不能滿足系統(tǒng)對(duì)業(yè)務(wù)的需要,導(dǎo)致老年代的空間常常被占滿,老年代的空間滿了,導(dǎo)致的Full GC。由于老年代的空間比較小,所以每次Full GC的時(shí)間也比較短。
A系統(tǒng)日志,只有2次Full GC,這2次GC均發(fā)生在系統(tǒng)啟動(dòng)時(shí):
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
老生代大小:1048576K=1024M
新生代大小:458752K=448M
分析:A系統(tǒng)只有系統(tǒng)啟動(dòng)才出現(xiàn)二次Full GC現(xiàn)象,而且是” Metadata GC Threshold”引起的,而不是堆空間引起的Full GC。雖然經(jīng)過(guò)一個(gè)星期的觀察,A系統(tǒng)沒(méi)有Full GC,但一旦發(fā)生Full GC時(shí)間則會(huì)比較長(zhǎng)。其它系統(tǒng)增加發(fā)現(xiàn)過(guò),1024M的老年代,Full GC持續(xù)的時(shí)間大約是90ms秒。所以看得出來(lái)推也不是越大越好,或者說(shuō)在UseParallelOldGC收集器中,堆的空間不是越大越好。
?
分析與優(yōu)化
總體分析:
B系統(tǒng)的Full GC過(guò)于頻繁,是因?yàn)槔仙挥屑s108M空間,根本無(wú)法滿足系統(tǒng)在高峰時(shí)期的內(nèi)存空間需求。由于ParOldGen(老年代)常常被耗盡,所以就發(fā)生Full GC事件了。
A系統(tǒng)的堆初始空間(Xms)和堆的最大值(Xmx)均為1536M,完全可以滿足業(yè)務(wù)高峰期的內(nèi)存需求。
優(yōu)化策略:
B系統(tǒng)先增加堆空間大小,即通過(guò)設(shè)置Xms、 Xmx值增加堆空間。直接把Xms和Xmx均設(shè)置為1024M。直接堆的啟動(dòng)空間(Xms)直接設(shè)置為堆的最大值的原因是:因?yàn)橹苯影裍ms設(shè)置為最大值(Xmx)可以避免JVM運(yùn)行時(shí)不停的進(jìn)行申請(qǐng)內(nèi)存,而是直接在系統(tǒng)啟動(dòng)時(shí)就分配好了,從而提高系統(tǒng)的效率。把Xms(堆大小)設(shè)置為1024M,是因?yàn)椴捎肑DK的建議,該建議通過(guò)命令得到” java -XX:+PrintCommandLineFlags -version” 。
其中,“-XX:MaxHeapSize=1004719104”,即Xmx為1024M,其它建議暫時(shí)不采納。所以綜合下來(lái)的B系統(tǒng)的JVM參數(shù)設(shè)置如下:export JAVA_OPTS="-server –Xms1024m -Xmx1024m -XX:+UseParallelOldGC -verbose:gc -Xloggc:../logs/gc.log -XX:+PrintGCDetails -XX:+PrintGCTimeStamps"
A系統(tǒng)JVM參數(shù)設(shè)置保持不變,以便觀察系統(tǒng)運(yùn)行情況,即:export JAVA_OPTS="-server -Xms1536m -Xmx1536m -XX:+UseParallelOldGC -verbose:gc -Xloggc:../logs/gc.log -XX:+PrintGCDetails -XX:+PrintGCTimeStamps"
將A、B節(jié)點(diǎn)系統(tǒng)的JVM參數(shù)采用2套參數(shù),是為了驗(yàn)證A或B的參數(shù)更適合實(shí)際情況。
總結(jié)
以上是生活随笔為你收集整理的一次生产的 JVM 优化案例的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 阿里P7试用期被淘汰,主管给出的理由让人
- 下一篇: 作为高管,你需要了解的五个ERP趋势