谈谈项目中主动 full gc 的一些问题

背景

前一段时间在公司一个技术群里,有人在问“有人在线上 使用32G内存的服务” 。我司线上内存标准配置都是8G的。我就问了一下使用32G内存碰到了啥问题。他的关注点在于一次full gc 时间的长短上。他们面临的问题是上游设置的超时时间太短,一旦他们服务发生full gc,上游服务必然超时。其实很多项目都会面临这个问题。我自己的解决方案就是主动full gc。并且在群里给出了相关的代码。没想到大家对这个主动full gc都很感兴趣,这几天不少人咨询了我这方面的事情。所以就写一篇文章来说说主动full gc。

主动 full gc的标准流程

主动full gc的流程应该如下:

  1. 检查是否快满足full gc条件,若到达临界点,进入2;

  2. 主动把服务给注册下线;

  3. 调用System.gc();

  4. 主动把服务注册上线;

如何检查old区域中的使用率呢?

SunJVM提供了一组内存检测接口MemoryPoolMXBean,可以在代码中直接调用这个接口检测各个内存使用情况,具体使用方式可以参考cathttps://github.com/dianping/cat)中的MemoryInformations。

如何检查是否到达临界点?

一般情况下我们只需要关注old区域即可(有些应用会生成临时类除外)。在使用CMS作为垃圾回收器的时候,我们只要检查old区域的使用率是否快要到达CMSInitiatingOccupancyFraction(并且加上参数UseCMSInitiatingOccupancyOnly,不要让JVM替我们 垃圾收集决策 )即可。

如何很好的把服务注册下线?

每个公司的基础组件可能都不同,但是一般情况下都会提供这样的功能。比如我司直接在代码中设置状态即可( configStatus.setRuntimeStatus(CustomizedStatus.DEAD); ),一行代码即可。但是一定要注意 从发起下线到真正下线,中间肯定有时间延迟;而且发起下线的时候服务本身还有一些请求需要处理完成才可以;所以发起线下之后,必须过一段时间才能执行主动GC。

如何很好的执行System.gc()?

你是不是认为这个很简单啊,直接调用 System.gc()即可?JDK中代码中有需要直接调用 System.gc(),那就看看别人别人怎么写的吧,可以参考DirectByteBuffer中的写法:

谈谈项目中主动 full gc 的一些问题

大家可以思考一下为什么要在调用System.gc()之后暂时一段时间。

还有要使System.gc()这个生效,必须在jvm中去掉 DisableExplicitGC这个参数。

如何优化主动 full gc

控制同时主动full gc机器数

主动full gc中最重要的就是要防止所有机器同时主动full gc,一旦所有机器同时full gc就可能造成上游服务感知不到服务在线了。如果项目中在这方面有比较严的要求,可以使用分布式信号量来保证同时只有特定数目的机器发生full gc;若不需要那么严格,可以让某些机器只在时间末尾为N的发生主动full gc。也就是说可以通过时间末尾来控制最多有1/N台机器主动发生full gc。

降低主动full gc的频率

假设一次主动full gc的的时间分为服务上下线时间 T1和 System.gc()执行时间 T2。一般情况下T1>>>T2,T2一般几百ms肯定就可以完成了;T1比较固定,基本上需要几秒甚至十几秒。 这样的话,如果主动降级full gc频率,那么T1的次数很明显下降很多;就算每次主动full gc T2时间上升了对整体停服时间也会降低很多。

那么调大old区域的大小肯定可以降低full gc频率。那能不能提高old的区域的使用率呢,也就是提高 CMSInitiatingOccupancyFraction的配置值。我们知道对于CMS有内存碎片化问题,所以这个参数一般配置的不是很大,比如默认的配置是68%。但是 调用System.gc()的时候,执行的不是CMS GC,而是full gc,不存在内存碎片化问题。 所以可以通过提高CMSInitiatingOccupancyFraction参数来降低full gc频率。

如何设置好主动full gc的临界点

首先、这个临界点肯定要低于 CMSInitiatingOccupancyFraction的配置,这样主动full gc才会生效。这个要结合full gc的频率以及主动full gc时的停服时间还有允许同时主动full gc的机器数目。一般的应用来说我们只要保证cms gc来临的前5分钟有主动full gc的机会就可以了。如果每分钟一次机会,那么4次机会都没有轮上主动full gc,那么我认为要么full gc太频繁了要么full gc时间都太集中了,不管哪种都应该需要优化了。观察一下cms gc前5分钟的old区域使用率设置为临界点即可。

主动 full gc的代码demo

谈谈项目中主动 full gc 的一些问题

总结

主动full gc还是有不少学问的,比如System.gc()前后的sleep、如何防止所有机器同时发生主动full gc、如何优化主动full gc频率等。

原文 

https://mp.weixin.qq.com/s/QoBtVzVjS8V8zDCLewKLLg

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » 谈谈项目中主动 full gc 的一些问题

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址