扩容?先尝试一下JVM调优吧

勿忘初心2018-10-19 18:43

此文已由作者吴桐授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验。



引言


随着接入的产品越来越多,URS线上集群每个季度都会对节点机进行扩容,来提高系统的服务性能,但是无限制的扩容对运维发布和管理是很大的负担。本文通过分析系统GC状况,对JVM参数进行调优,最终改善了整个集群的服务性能。


现状


通过哨兵JVM监控,可以看到主机的GC状况非常糟糕!

 从上图可以看出,系统每2分钟YGC 15次左右,Full GC大概每四分钟一次,YGC 时间平均约120ms左右,FGC时间约200ms左右。
所以我们的目标很明确:
1)降低FGC频率
2)降低YGC频率


排查


step1 查看JVM参数配置:


-J-Xms6g-J-Xmx6g -J-Xmn1g -J-XX:MaxPermSize=256m 
-J-XX:+UseParNewGC -J-XX:+UseConcMarkSweepGC -J-XX:+UseCMSCompactAtFullCollection -J-XX:CMSFullGCsBeforeCompaction=0 -J-XX:+CMSClassUnloadingEnabled -J-XX:+CMSParallelRemarkEnabled -J-XX:+CMSScavengeBeforeRemark -J-XX:CMSInitiatingOccupancyFraction=60

配置说明:堆内存大小为6G,年轻代大小为1G,Survivor区采用默认值8,perm区大小为256M,年轻态采用UseParNewGC策略(注意:该策略是多线程并发,也是stop-the-world的),老年代采用UseCMSCompactAtFullCollection策略,在老年态达到60%时开始触发Full GC。


step2 原因推测


通过jstat查看JVM GC的详细信息如下: 

从图中可以看出以下现象:
1)Eden区增长过快,大概在10-12秒满了,触发一次YGC 
2)Survivor区始终是100% 
3)old区增长过快,每次YGC后old区都会有1.5%左右的增长 
根据经验,可以初步推断原因是:Survivor空间太小,导致部分对象直接从Eden区晋升到old区。


step3 确认


JVM增加-XX:+PrintTenuringDistribution,将gc详细信息打印出来,发现:


 434.461: [GC 434.461: [ParNew
Desired survivor size 53673984 bytes, new threshold 1 (max 4)
- age   1:  102263096 bytes,  102263096 total
: 943744K->104832K(943744K), 0.0926790 secs] 2356325K->1547627K(6186624K), 0.0930940 secs] [Times: user=0.18 sys=0.00, real=0.09 secs]
446.155: [GC 446.156: [ParNew
Desired survivor size 53673984 bytes, new threshold 1 (max 4)
- age   1:  101646648 bytes,  101646648 total
: 943744K->104831K(943744K), 0.0769350 secs] 2386539K->1565608K(6186624K), 0.0773370 secs] [Times: user=0.16 sys=0.00, real=0.08 secs]

发现每次YGC完,age1的存活对象超过一大半,确实存在过早晋升的现象。


step4 验证


调整JVM参数,设置-J-XX:SurvivorRatio=4,效果很明显,发现FGC降下来了,大概一个小时FGC一次,但是YGC和有所上升。


调优


JVM各个参数之间有一个平衡性的,另外根据业务类型和实际的运行环境都有不一样的效果。但是有些约定俗成的规定还是值得借鉴的:
1)堆内存不超过物理内存的3/4 
2)年轻代的大小不超过堆内存的3/8 
2)CMSInitiatingOccupancyFraction一般不低于70% 
根据上面三条再结合网上老司机总结出来的公式:


(Xmx-Xmn)*(1-CMSInitiatingOccupancyFraction/100)>=(Xmn-Xmn/(SurvivorRatior+2))

得出两组JVM参数: 第一组:


xms=6G
xmn=6G
survivor=4
xmn=2G
CMSInitiatingOccupancyFraction=70

第二组:


xms=6G
xmn=6G
survivor=3
xmn=1.75G= 1792M
CMSInitiatingOccupancyFraction=70

经过线上灰度,发现第二组参数效果更优。通过灰度发现FGC和YGC都有了降低,系统的性能提高了。优化后的效果如下: 



总结


Java应用的JVM调优是个细活,需要结合业务特点不断反复的去尝试和分析,但是带来的效益是巨大的。通过本次优化,URS的线上集群的吞吐量和稳定性都比之前更好了,扩容的需求也变少了。


网易云免费体验馆,0成本体验20+款云产品! 

更多网易技术、产品、运营经验分享请点击


相关文章:
【推荐】 Puppeteer入门初探
【推荐】 网站验证码WEB前端接入实例
【推荐】 4月第4周业务风控关注|网络犯罪经济每年1.5万亿美元GDP居全球第12位