【面试拿来即用系列你遇到过什么线上问题,如何解决的?(四)

2023年 10月 12日 67.0k 0

一、缘起

在一个阳光明媚的周五傍晚,虽然还未到周末,但我已然沉浸在这即将到来的自由时光中无法自拔。秃然,奇怪的事情发生了~

一个服务在疯狂的FULLGC报警,把我的思绪从美好的吃喝玩乐中拉回了现实,周五下班前出问题的魔咒又来了吗?

PS:
本文是线上问题系列的第四篇,主题为频繁Full GC问题的排查与解决方法论

注:本案例为中大型互联网公司遇到的真实案例(没错,就是我亲自遇到的……),其知识点的深度和广度拿来面试都足够,建议认真阅读并且熟悉涉及到的相关知识点。若有任何问题可在评论区指出~

二、奇怪的现象

image.png

三、案发背景&现场

在排查FULLGC问题前,尽可能的抓住所有的案发现场证据,手里有更多的牌,以便让我们应对的更自如

3.1 这是个什么服务?

首先了解下这是个什么服务?

ECP是一个将数据从不同的数据源(如文件,Mysql,TIDB)等将数据同步到ES中的服务,里面的实现逻辑总体可以解释为:

把数据从数据源拉出来,再塞到ES里面去。因此里面涉及到了大量的数据操作

里面涉及到的大量细节,如大数据量读取、SPI机制、QPS限制、索引管理等后面会出个【设计亮点系列】来描述,在这里只介绍和GC问题相关的一些流程

image.png

由于该服务为数据同步服务,不像业务服务一直有请求,在触发频繁Full GC的时候,当前无正在进行中的任务

image.png

3.2 FULLGC的情况

如下图监控平台是15秒上报一次值,15秒大概8次Full GC,频次已经相当高了,GC耗时也不短

image.png

如下图,Full GC是在晚上20.52突然起来的,经过查看,此时正有一个9000多w数据同步的任务正在进行中,该任务于凌晨1点结束,任务结束后Full GC依然继续,没有停下的迹象

GC图:

任务图:
9000多w数据的任务

3.3 服务机器情况

ECP总共有两台机器,只有一台机器在不断的在Full GC,而这台机器就是任务执行的机器,说明该Full GC问题和任务执行强相关

3.4 服务JVM的参数设置

  • XX:MetaspaceSize=256m: 设置Metaspace初始大小为256MB。Metaspace用于存储类的元数据,包括类的结构、方法信息等。
  • XX:MaxMetaspaceSize=256m: 设置Metaspace的最大大小为256MB。Metaspace会根据需要动态增长,但不会超过这个限制。
  • XX:+UseParNewGC: 启用ParNew垃圾收集器,用于新生代的垃圾收集。ParNew是一种多线程的垃圾收集器,用于新生代的并行收集。
  • XX:+UseConcMarkSweepGC: 启用CMS(Concurrent Mark and Sweep)垃圾收集器,用于老年代的垃圾收集。CMS是一种以最短停顿时间为目标的垃圾收集器。
  • XX:+UseCMSCompactAtFullCollection: 启用CMS在Full GC(完全垃圾回收)时进行内存碎片整理。这有助于减少内存碎片,提高内存利用率。
  • XX:CMSInitiatingOccupancyFraction=80: 设置CMS触发垃圾回收的老年代占用比例阈值为80%。当老年代占用达到这个比例时,CMS会启动垃圾回收。
  • Xms4g: 设置JVM的初始堆大小为4GB。JVM启动时分配的堆的最小值。
  • Xmx4g: 设置JVM的最大堆大小为4GB。JVM堆的最大允许大小。
  • Xmn2g: 设置新生代的大小为2GB。新生代是堆的一部分,用于分配新对象。

该服务新生代使用ParNewGC垃圾收集器,老年代使用CMS垃圾收集器 ,总堆4G,新生代2G,老年代2G,元空间256MB

3.5 JVM的内存变化情况

JVM相关区域内存变化如图:

image.png

四、猜想

如果一个现象发生了,那么我们需要在脑海中穷举所有的可能性,然后一一去确认(这里需要一定的知识储备哦),既然是频繁的FULLGC,那么FULLGC的触发条件是什么呢?(在老年代为CMS收集器的情况下)

  • 老年代空间不足(CMS GC、G1 GC): 当老年代的空间不足时,JVM 会触发 Full GC,尝试回收老年代中的无用对象。
  • 永久代或 Metaspace 空间不足: 在永久代(Java 7 及之前)或 Metaspace(Java 8+)空间不足时,也会触发 Full GC,尝试回收永久代或 Metaspace 中的无用对象。
  • Minor GC晋升到老年代的平均大小大于老年代的剩余空间,其实也是老年代的空间不足了
  • Cocurrent mode failure ,在执行CMS GC的过程中,如果此时有线程将对象放入老年代,并且老年代空间不足,或者在做Minor GC的时候,新生代Survivor空间不足,需要放入老年代,而老年代空间也不足,则触发Full GC。---其实也是老年代空间不足了
  • 系统调用 System.gc()
  • 总结一下,Full GC的触发条件其实就是以下三大类:

    image.png

    当知晓了Full GC的触发条件,频繁Full GC也就是上面三个条件不断得被触发而已

    五、猜想验证

    对于第一种情况:system.gc()的调用,直接利用idea全局搜索即可,这个简单,验证完没问题直接跳过

    对于第二种情况,ecp服务配置的元空间大小为256MB,一般公司都有较为完善的监控系统来观察这类值的变化,如下图,ECP服务的元空间占用为102MB,也可以排除

    image.png

    对于第三种情况,看下老年代的占用,发现已经到了最大值2g,而且回收并没有让老年代占用的内存空间变小,这样问题就比较明显了,大概率是内存泄露导致的,如下图。

    image.png

    什么是内存泄露?内存泄漏指的是程序在运行过程中,未能正确地释放不再需要使用的内存,导致这些内存无法被回收,长时间累积造成系统内存消耗过多的现象。简单来说,就是程序在使用内存时“丢失”了一部分内存,不再能够访问和释放它们。

    至此频繁Full GC的问题已经明确,即老年代的使用达到阈值,因此触发Full GC进行回收,但回收完空间占用依然达到使用阈值,因此不断的触发Full GC进行回收

    六、问题追溯与解决

    明确了是因为内存泄露导致频繁的Full GC,那就需要定位导致内存泄露的问题代码在什么位置?那定位流程是什么呢?以下列举了追踪路径:

  • 将节点的流量摘掉,保证没有业务访问该服务,避免影响到线上业务
  • DUMP节点的内存快照
  • 利用MAT工具分析内存泄露的对象
  • 找到操作该对象的代码,利用IDEA的代码调用追溯找到调用链
  • 审视代码调用链的逻辑
  • 总的来说,就是找到无法回收的内存对象,看下什么地方操作了这些对象,排查下有没有问题

    实战一下:

  • 摘掉该节点的流量,这个一般公司的基础组件会提供该能力,如下图:
  • image.png

  • 利用Arthas dump(Jmap也可)下来堆内存里面存活的对象
  • image.png

  • 利用MAT对象分析dump下来的内存快照,检测到了内存泄露的问题
  • image.png

    还可以看到对象的引用链,可以发现ZhuanZhuanRegistry里面的serviceListenersMap占用暴涨

    image.png

  • 找到向serviceListenersMap 存放数据的方法,利用IDEA的方法调用追溯找到整条调用链(在MAC上的快捷键是option+command+H),如下图
  • image.png

    5.发现ECP服务中的一段用于推送数据的方法(reference.refer()),在每次调用的时候,其底层都会向map中put一个值,在大数据量的时候,频繁调用,最终导致内存溢出,如下图:

    image.png

    image.png

    七、修复

    将reference.refer()的结果放入到Map中,每次调用的时候从Map中取,取不到的时候再创建,如下图:

    image.png

    至此,后续的大数据量任务再也没有Full GC的问题了,完美~

    八、总结

    当遇到频繁Full GC的问题时,如果已经影响到线上业务了,那就快速解决,先把一台机器的流量摘掉,其余机器重启,这样不但可以保留案发现场,并可以快速解决问题。

    在摘掉流量的机器上,可以利用jmap或arthas将内存快照dump下来进行分析,以定位为什么会频繁的触发full gc~

    当然我们需要对full gc的触发有系统级的理解,这样才可知彼知己,百战不殆

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论