jvm性能调优实战 - 35电商APP后台系统如何对Full GC进行深度优化

简介: jvm性能调优实战 - 35电商APP后台系统如何对Full GC进行深度优化

业务背景

这个JVM性能优化的案例,很多核心的思想其实也跟之前是相同的,只不过在优化的过程中会带出来一些比较高级的参数的调优。

业务背景,这是一个垂直电商公司,一些细分领域的电商业务.

注册用户量有就数百万的规模,每日活跃用户数量几十万,每天APP的整体请求量也就小几千万的级别,也并不大。高峰期的QPS也就每秒数百请求

但即使如此的一个普通APP的后台系统,感觉上压力一点儿都不大,是不是真的就没有JVM的性能问题呢?

当然不是了,这个APP虽然不大,但是他同样有JVM相关的性能问题,而且也需要一些细致的优化才可以。


JVM性能问题

部署生产环境的时候往往就不会对JVM进行什么参数的设置,可能很多时候就是用一些默认的JVM参数。

默认的JVM参数绝对是系统负载逐渐增高的时候一个最大的问题 . 前期是没什么问题,但是中后期开始,当有一定用户量,有一定负载了,此时就会出现一些问题了。

新生代内存过小,会导致Survivor区域内存过小,同时Eden区域也很小。

Eden区域过小,自然会导致频繁的触发Young GC,Survivor区域过小,自然会导致经常在Young GC之后存活对象其实也没多少,但就是Survivor区域放不下。

此时必然会导致对象经常进入老年代中,因此也必然会导致老年代过一段时间就放满了,然后就会触发Full GC。

所以当时这个垂直电商APP的各个系统通过jstat分析JVM GC之后发现,基本上高峰期的时候,Full GC每小时都会发生好几次。

Full GC一般在正常情况下,都是以天为单位发生的,比如每天发生一次,或者是几天发生一次Full GC。

要是每小时都发生几次Full GC,那么就会导致系统每小时都卡顿好几次。这个时候必然是不行的。

分析系统情况过后,定制了一套公司级别的JVM参数模板

在大部分工程师都对JVM优化不是很精通的情况下,通过推行一个JVM参数模板,让各个系统短时间内迅速就优化了JVM的性能。


如果你是一个团队的leader,或者是一个中小型公司的架构师,那么必然是需要为团队或者公司定制一套基本的JVM参数模板的

然后尽量让大部分系统套用这个模板,基本保证JVM性能别太差,避免很多初中级工程师直接使用默认的JVM参数,可能一台8G内存的机器上,JVM堆内存就分配了几百MB。

下面定制出来的适合他们公司的JVM参数模板:

-Xms4096M -Xmx4096M -Xmn3072M -Xss1M  -XX:PermSize=256M -XX:MaxPermSize=256M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=92 -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0

为什么如此定制JVM参数模板呢?

首先,8G的机器上给JVM堆内存分配4G就差不多了,毕竟可能还有其他进程会使用内存,一般别让JVM堆内存把机器内存给占满。

然后年轻代给到3G,之所以给到3G的内存空间,就是因为让年轻代尽量大一些,进而让每个Survivor区域都达到300MB左右。

根据当时对这个业务系统的分析,假设用默认的JVM参数,可能年轻代就几百MB的内存,Survivor区域就几十MB的内存

那么每次垃圾回收过后存活对象可能会有几十MB,这是因为在垃圾回收的一瞬间可能有部分请求没处理完毕,此时会有几十MB对象是存活的,所以很容易触发动态年龄判定规则,让部分对象进入老年代。

所以在分析过后,给年轻代更大内存空间,让Survivor空间更大,这样在Young GC的时候,这一瞬间可能有部分请求没处理完毕,有几十MB的存活对象,这个时候在几百MB的Survivor空间中可以轻松放下,绝对不会进老年代。

基本上在这个内存分配之下,对于这个垂直电商APP的大部分后台业务系统,都是可以轻松hold住的

不同的系统运行时的情况略有不同,但是基本上都是在每次Young GC过后存活几MB~几十MB的对象,所以此时在这个参数模板下,都可以抗住。

只要把内存分配完毕,那么对象进入老年代的速度是极慢极慢的,经过这个参数模板 ,通过jstat观察,基本上发现各个系统的Full GC都变成了几天才会发生一次。

此时在参数模板里还会加入Compaction相关的参数,保证每次Full GC之后都会执行一次压缩,解决内存碎片的问题。


如何优化每次Full GC的性能?

再介绍一下优化的时候调整的另外两个参数,这个两个参数可以帮助优化FUll GC的性能,把每次Full GC的时间进一步降低一些。

  • 一个参数是“-XX:+CMSParallelInitialMarkEnabled”,这个参数会在CMS垃圾回收器的“初始标记”阶段开启多线程并发执行。

大家应该还记得初始标记阶段,是会进行Stop the World的,会导致系统停顿,所以这个阶段开启多线程并发之后,可以尽可能优化这个阶段的性能,减少Stop the World的时间。

  • 另外一个参数是“-XX:+CMSScavengeBeforeRemark”,这个参数会在CMS的重新标记阶段之前,先尽量执行一次Young GC。

这样做有什么作用呢?

其实大家都记得,CMS的重新标记也是会Stop the World的,所以所以如果在重新标记之前,先执行一次Young GC,就会回收掉一些年轻代里没有人引用的对象。

所以如果先提前回收掉一些对象,那么在CMS的重新标记阶段就可以少扫描一些对象,此时就可以提升CMS的重新标记阶段的性能,减少他的耗时。

所以当时在JVM参数模板中,同样加入了这两个参数:

-Xms4096M -Xmx4096M -Xmn3072M -Xss1M  -XX:PermSize=256M -XX:MaxPermSize=256M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFaction=92 -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSParallelInitialMarkEnabled -XX:+CMSScavengeBeforeRemark

调优后的效果

经过各个团队采用jstat观察JVM GC情况,发现明显有了很大的好转,基本上各个系统的Young GC都在几分钟一次,或者十几分钟一次,每次耗时就几十毫秒而已。

Full GC基本都在几天一次,每次耗时在几百毫秒的样子。

基本上各个系统的JVM达到这个性能,就对线上系统没多大影响了。哪怕是不太懂JVM优化的普通工程师只要套用这个模板,对一些普通的业务系统,都能保证其JVM性能不会出现大的问题,比如频繁的Young GC和Full GC导致的系统频繁卡顿。


思考

  • 你们公司有没有类似这里讲的JVM参数模板?
  • 假如你是公司的架构师,结合你们公司的大部分业务系统的实际情况,会如何定制一套JVM参数模板?
  • 是否你们公司有各种不同配置的机器?
  • 针对不同配置的机器如何定制JVM参数模板?
  • 你们公司有没有那种特例的系统,比如并发量特别高或者数据量非常大?
  • 对特例系统该如何进行优化?


相关文章
|
10月前
|
搜索推荐 开发工具 UED
apptrace 三大策略,助力电商 App 在 618 突围​
随着“618”电商大促预售开启,各大平台投入百亿流量与现金争夺用户。然而,网络购物市场增量空间趋于饱和,电商App亟需突破曝光、拉新与转化瓶颈。apptrace提供三大增长策略:精准曝光通过智能广告监测优化投放;裂变拉新简化流程,助力社交传播;高效转化实现一键直达活动页面,提升用户体验与留存率。这些技术优势助力开发者和运营者在618大战中抢占先机,实现用户增长与商业价值最大化。
|
12月前
|
监控 数据可视化 数据挖掘
【开发者必看—电商篇】数据赋能电商类App转化率循序增长
通过友盟+ 数据分析工具,团队深入分析了用户行为路径、转化漏斗、停留时间及错误事件等关键数据,定位到用户体验与产品性能的问题。经过精准优化,包括简化购物流程、修复技术故障及提升稳定性,最终显著提高了用户转化率。这一案例展示了数据驱动在产品优化中的重要作用。
【开发者必看—电商篇】数据赋能电商类App转化率循序增长
|
监控 Java 编译器
Java虚拟机调优指南####
本文深入探讨了Java虚拟机(JVM)调优的精髓,从内存管理、垃圾回收到性能监控等多个维度出发,为开发者提供了一系列实用的调优策略。通过优化配置与参数调整,旨在帮助读者提升Java应用的运行效率和稳定性,确保其在高并发、大数据量场景下依然能够保持高效运作。 ####
379 58
|
监控 架构师 Java
Java虚拟机调优的艺术:从入门到精通####
本文作为一篇深入浅出的技术指南,旨在为Java开发者揭示JVM调优的神秘面纱,通过剖析其背后的原理、分享实战经验与最佳实践,引领读者踏上从调优新手到高手的进阶之路。不同于传统的摘要概述,本文将以一场虚拟的对话形式,模拟一位经验丰富的架构师向初学者传授JVM调优的心法,激发学习兴趣,同时概括性地介绍文章将探讨的核心议题——性能监控、垃圾回收优化、内存管理及常见问题解决策略。 ####
|
监控 搜索推荐 数据挖掘
【开发者必看—电商篇】数据赋能电商App活跃度重焕新生
通过友盟+数据分析工具的综合数据分析和个性化推送功能,解决APP用户活跃度迅速下降的问题。
|
算法 网络协议 Java
【JVM】——GC垃圾回收机制(图解通俗易懂)
GC垃圾回收,标识出垃圾(计数机制、可达性分析)内存释放机制(标记清除、复制算法、标记整理、分代回收)
|
Arthas 监控 Java
JVM进阶调优系列(9)大厂面试官:内存溢出几种?能否现场演示一下?| 面试就那点事
本文介绍了JVM内存溢出(OOM)的四种类型:堆内存、栈内存、元数据区和直接内存溢出。每种类型通过示例代码演示了如何触发OOM,并分析了其原因。文章还提供了如何使用JVM命令工具(如jmap、jhat、GCeasy、Arthas等)分析和定位内存溢出问题的方法。最后,强调了合理设置JVM参数和及时回收内存的重要性。
|
监控 Java 测试技术
Elasticsearch集群JVM调优垃圾回收器的选择
Elasticsearch集群JVM调优垃圾回收器的选择
503 1
|
监控 Java 编译器
Java虚拟机调优实战指南####
本文深入探讨了Java虚拟机(JVM)的调优策略,旨在帮助开发者和系统管理员通过具体、实用的技巧提升Java应用的性能与稳定性。不同于传统摘要的概括性描述,本文摘要将直接列出五大核心调优要点,为读者提供快速预览: 1. **初始堆内存设置**:合理配置-Xms和-Xmx参数,避免频繁的内存分配与回收。 2. **垃圾收集器选择**:根据应用特性选择合适的GC策略,如G1 GC、ZGC等。 3. **线程优化**:调整线程栈大小及并发线程数,平衡资源利用率与响应速度。 4. **JIT编译器优化**:利用-XX:CompileThreshold等参数优化即时编译性能。 5. **监控与诊断工