线上FullGC问题排查实践——手把手教你排查线上问题 | 京东云技术团队

news2024/11/20 6:34:18

作者:京东科技 韩国凯

一、问题发现与排查

1.1 找到问题原因

问题起因是我们收到了jdos的容器CPU告警,CPU使用率已经达到104%

image-20230421152602849

观察该机器日志发现,此时有很多线程在执行跑批任务。正常来说,跑批任务是低CPU高内存型,所以此时考虑是FullGC引起的大量CPU占用(之前有类似情况,告知用户后重启应用后解决问题)。

通过泰山查看该机器内存使用情况:

image-20230421152933510

可以看到CPU确实使用率偏高,**但是内存使用率并不高,只有62%,**属于正常范围内。

到这里其实就有点迷惑了,按道理来说此时内存应该已经打满才对。

后面根据其他指标,例如流量的突然进入也怀疑过是jsf接口被突然大量调用导致的cpu占满,所以内存使用率不高,不过后面都慢慢排除了。其实在这里就有点一筹莫展了,现象与猜测不符,只有CPU增长而没有内存增长,**那么什么原因会导致单方面CPU增长?**然后又朝这个方向排查了半天也都被否定了。

后面突然意识到,会不会是监控有“问题”?

换句话说应该是我们看到的监控有问题,这里的监控是机器的监控,而不是JVM的监控!

JVM的使用的CPU是在机器上能体现出来的,而JVM的堆内存高额使用之后在机器上体现的并不是很明显。

遂去sgm查看对应节点的jvm相关情况:

image-20230421154928774

可以看到我们的堆内存老年代确实有过被打满然后又清理后的情况,查看此时的CPU使用情况也可以与GC时间对应上。

那么此时可以确定,是Full GC引起的问题。

1.2 找到FULL GC的原因

我们首先dump出了gc前后的堆内存快照,

然后使用JPofiler进行内存分析。(JProfiler是一款堆内存分析工具,可以直接连接线上jvm实时查看相关信息,也可以分析dump出来的堆内存快照,对某一时刻的堆内存情况进行分析)

首先将我们dump出来的文件解压,修改后缀名.bin,然后打开即可。(我们使用行云上自带的dump小工具,也可以自己去机器上通过命令手工dump文件)

image-20230421155755209

首先选择Biggest Objects,查看当时堆内存中最大的几个对象。

从图中可以看出,四个List对象就占据了近900MB的内存,而我们刚刚看到堆内存最大也只有1.3GB,因此再加上其他的对象,很容易就会把老年代占满引发full gc的问题。

image-20230421160135305

选择其中一个最大的对象作为我们要查看的对象

这个时候我们已经可以定位到对应的大内存对象对应的位置:

image-20230421160241646

其实至此我们已经能够大概定位出问题所在,如果还是不确定的话,可以查看具体的对象信息,方法如下:

image-20230421160532920

可以看到我们的大List对象,其实内部是很多个Map对象,而每个Map对象中又有很多键值对。

在这里也可以看到Map中的相关属性信息。

也可以在以下界面直接看到相关信息:

image-20230421160715617

然后一路点下去就可以看到对应的属性。

至此,我们理论上已经找到了大对象在代码中的位置。

二、问题解决

2.1 找到大对象在代码中的位置与问题的根本原因

首先我们根据上述过程找到对应位置与逻辑

我们的项目中大概逻辑是这样的:

  1. 首先会解析用户上传的Excel样本,并将其加载到内存中作为一个List变量,即我们上述看到的变量。一个20w的样本,此时字段数量有a个,大概占用空间100mb左右。
  2. 然后遍历循环用户样本,根据用户样本中的数据,再增加一些额外的请求数据,根据此数据请求相关结果。此时字段数量有a+n个,占用空间已经在200mb左右。
  3. 循环完成后将此200mb的数据存入缓存。
  4. 开始生成excel,将200mb数据从缓存中取出,并根据之前记录的a个字段,取出初始的样本字段填充至excel。

用流程图表示为:

jvmgc-Page-1.drawio

结合一些具体排查问题的图片:

image-20230421172512115

其中一个现象是每次gc后的最小内存正在逐步变大,对应上述步骤中第二步,内存正在逐步膨胀。

结论

将用户上传的excel样本加载到内存中,并将其作为一个List<Map<String, String>>的结构存储起来,首先一个20mb的excel文件以此方式存储会膨胀占用120mb左右堆内存,此步骤会大量占用堆内存,并且因为任务逻辑原因,该大对象内存会在jvm中存在长达4-12小时之久,导致一但任务过多,jvm堆内存很容易被打满。

这里列举了为什么使用HashMap会导致内存膨胀,其主要原因是存储空间效率比较低:

一个Long对象占内存计算:在HashMap<Long,Long>结构中,只有Key和Value所存放的两个长整型数据是有效数据,共16字节(2×8字节)。这两个长整型数据包装成java.lang.Long对象之后,就分别具有8字节的MarkWord、8字节的Klass指针,再加8字节存储数据的long值(一个包装对象占24字节)。

然后这2个Long对象组成Map.Entry之后,又多了16字节的对象头(8字节MarkWord+8字节Klass指针=16字节),然后一个8字节的next字段和4字节的int型的hash字段(8字节next指针+4字节hash字段+4字节填充=16字节),为了对齐,还必须添加4字节的空白填充,最后还有HashMap中对这个Entry的8字节的引用,这样增加两个长整型数字,实际耗费的内存为(Long(24byte)×2)+Entry(32byte)+HashMapRef(8byte)=88byte,空间效率为有效数据除以全部内存空间,即16字节/88字节=18%。

——《深入理解Java虚拟机》5.2.6

以下是刚上传的excel中dump出的堆内存对象,其占用的内存达到了128mb,而上传的excel实际只有17.11mb。

image-20230423145825354

image-20230423145801632

空间效率17.1mb/128mb≈13.4%

2.2 如何解决此问题

暂且不讨论上述流程是否合理,解决办法一般可以分为两类,一类是治本,即不把该对象放入jvm内存中,转而存入缓存中,不在内存中则大对象问题自然迎刃而解。另一类是治标,即缩小该大内存对象,在日常使用场景下使其一般不会触发频繁的full gc问题。

两种方式各有优劣:

2.2.1 激进治疗:不把他存入内存

解决逻辑也很简单,例如在加载数据时,将其按照样本加载数据一条一条存入redis缓存,然后我们只需要知道样本中有多少的数量,按照数量的先后顺序从缓存中取出数据,即可解决该问题。

优点:可以从根本上解决此问题,以后基本上不会存在该问题,数据量再大只需要添加相应的redis资源即可。

缺点:首先会增加许多redis缓存空间消耗,其次从显示考虑对于我们项目来说,此处代码古老且晦涩难懂,改动需要较大工作量与回归测试。

伏羲运营后台fullgc-第 2 页.drawio

2.2.2 保守治疗:缩减其数据量

分析2.1的上述流程,首先第三步是完全没必要的,先存入缓存再取出,额外占用缓存空间。(猜测系历史问题,此处不再深究)。

其次是在第二步中,多出来的字段n,在请求结束后该字段就已经无用了,因此可以考虑在请求结束后删除无用字段。

此时也有两种解决方案,一种是只删除无用字段缩减其map大小,然后将其作为参数传递给生成excel使用;另一种方式是请求完成直接删除该map,然后在生成excel时再重新读取用户上传的excel样本。

优点:改动较小,不需要太复杂的回归测试

缺点:在极端大数据量情况下,仍有可能出现full gc的情况

jvmgc-第 3 页.drawio

具体实现方式就不展开了。

其中一种实现方式

//获取有用的字段
String[] colEnNames = (String[]) colNameMap.get(Constant.BATCH_COL_EN_NAMES);
List<String> colList = Arrays.asList(colEnNames);
//去除无用的字段
param.keySet().removeIf(key -> !colList.contains(key));

三、拓展思考

首先本文中监控图是在复现当时场景时人为制造的gc常见。

在cpu使用率图中,大家可以观察到cpu使用率上升时间确实跟gc的时间相吻合,但是并没有出现当时场景中的104%的CPU使用率

image-20230423103730420

image-20230423103800435

其实直接原因比较简单,就是因为系统虽然出现了full gc,但是并没有频繁出现。

小范围低频率的full gc不太会引起系统的cpu飙升,这也是我们所看到的现象。

那么当时的场景是什么原因呢?

image-20230423105534963

我们上文提到过,我们在堆内存中的大对象是会随着任务的进行逐步膨胀的,那么当我们的任务足够多,时间足够长,就有可能导致每次full gc后可用空间变得越来越小,当可用空间小到一定程度之后就,每次full gc完成之后发现空间还是不够使用,就会触发下一次的gc,从而导致最终结果的频繁发生gc,引起cpu频率的飙升不下。

四、问题排查总结

  • 当我们遇到线上cpu使用率过高的情况时,可以先查看是否是full gc引起的问题,注意要看的是jvm的监控,或者使用jstat相关命令查看。不要被机器内存监控所误导。
  • 如果确定是gc引起的问题,可以通过JProfiler直连线上jvm或者使用dump保存堆快照后离线分析。
  • 首先可以找到最大的对象,一般情况下是大对象引起的full gc。还有一种情况是,不像这么明显是四个大对象,也可能是比较均衡的十几个50mb的对象,具体情况还需要具体分析。
  • 通过上述工具找到确定有问题的对象后找到其堆栈对应的代码位置,通过代码分析找到问题的具体原因,通过其他现象推演猜测是否正确,进而找到问题的真正原因。
  • 根据问题的原因解决此问题。

当然,上述只是不算很复杂的排查情况,不同的系统肯定有不同的内存情况,我们应当具体问题具体分析,而从此次问题中可以学到的就是如果排查解决问题的思路。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/491923.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【马蹄集】第九周作业

第九周作业 目录 MT2125 一样的虫子MT2126 AB数对MT2127 权值计算MT2128 黑客小码哥MT2129 来给单词分类 MT2125 一样的虫子 难度&#xff1a;黄金    时间限制&#xff1a;1秒    占用内存&#xff1a;128M 题目描述 有 N 只虫子&#xff0c;每只虫子有6条腿&#xff0c;每…

通过Python的pytesseract库识别图片中的文字

文章目录 前言一、pytesseract1.pytesseract是什么&#xff1f;2.安装pytesseract3.查看pytesseract版本4.安装PIL5.查看PIL版本 二、Tesseract OCR1.Tesseract OCR是什么&#xff1f;2.安装Tesseract OCR3.安装 Tesseract OCR 语言包 三、使用方法1.引入库2.打开图片文件3.使用…

聊一聊 Valgrind 监视非托管内存泄露和崩溃

一&#xff1a;背景 1. 讲故事 只要是程序总会出现各种莫名其妙的问题&#xff0c;比如&#xff1a;非托管内存泄露&#xff0c;程序崩溃&#xff0c;在 Windows 平台上一般用微软自家的官方工具 App Verifier 就可以洞察&#xff0c;那问题出在 Linux 上怎么办呢&#xff1f…

块状链表实现BigString大字符串操作(golang)

前言 块状链表是介于链表和数组之间的数据结构&#xff0c;能够在 O ( n ) O(\sqrt{n}) O(n ​)时间内完成插入、删除、访问操作。 数据结构如图所示。假设最大容量为 n n n, 则它有一个长度为 s n s\sqrt{n} sn ​的链表。链表中每个结点是一个长度为 2 n 2 \times \sqrt{…

C#_各类应用程序

目录 前言 1. 第一个程序&#xff1a;Hello&#xff0c;World&#xff01; 1.1 Console 1.2 Windows Forms 1.3 WPF&#xff08;Windows Presentation Foundation&#xff09; 1.4 ASP.NET Web Forms 1.5 ASP.NET MVC(Model - View - Controller) 1.6 Windows Store A…

Tuxera NTFS2023Mac专业NTFS驱动软件 解决Mac不能写入移动硬盘U盘问题 管理修复磁盘

Tuxera NTFS2023Mac专业NTFS驱动软件 解决Mac不能写入移动硬盘U盘问题 管理修复磁盘问题! NTFS For Mac2023是一款功能强大的MAC读写软件。NTFS For Mac可以帮助用户对磁盘进行日常管理&#xff0c;如果用户电脑的磁盘有问题&#xff0c;可以使用该软件进行修复&#xff0c;延…

Chatgpt系列(一) 如何使用chatgpt

系列文章目录 第一章: 如何使用chatgpt 第二章: chatgpt的概述 第三章: langchain入门 第四章: index 第五章: prompt 目录 系列文章目录 前言 一、LLM是什么&#xff1f; 二、使用步骤 1.学习地址 2.阅读内容重点的介绍 2.答复 读入数据 总结 系列文章目录前言一…

0基础学Java必备的50个知识点

1、编写&#xff1a;编写的Java代码保存在以“.java”结尾的源文件中。 2、编译&#xff1a;使用javac.exe命令编译java源文件&#xff0c;生成字节码文件。 格式&#xff1a;javac 源文件名.java 3、运行&#xff1a;使用java.exe命令解释运行字节码文件。格式&#xff1a;…

Linux笔记3

目录 一、root用户1.su命令2.sudo命令 二、vi/vim编译器1.三种工作模式2.命令模式3.底线命令模式 三、用户和用户组1.用户组管理2.用户管理3.getent命令 四、权限1.查看权限控制信息2.chmod 命令3.chown 命令 五、常用快捷键1.Ctrlc2.Ctrld3.历史命令4.光标移动快捷键 一、root…

亚马逊云科技和安恒信息,发布云原生SaaS主机安全和云原生堡垒机

4月19日&#xff0c;安恒信息首次举行了以“新见未来 实现梦想”为主题的年度新品发布会。来自产业界、投资界、财经界、媒体界等多方代表共同见证了本次发布会。这也是安恒信息自成立以来&#xff0c;首次大规模、高密度地发布新品。 联合产品发布 云原生SaaS主机安全与云原…

Linux 指令(一)+完整思维导图+实图例子+深入细节+通俗易懂建议收藏

绪论 在上一章&#xff0c;我们已经将Linux环境的安装起来了&#xff0c;从本章开始&#xff0c;我们将正式的进入到Linux的学习&#xff0c;Linux的学习还是比较的枯燥无味的&#xff0c;但我们要吃得苦中苦&#xff0c;让我们一起加油&#xff0c;进大厂拿到心仪的offer&…

黑马程序员-职工管理系统实战-附加源码Git

1、管理系统需求 职工管理系统可以用来管理公司内所有员工的信息 本教程主要利用C来实现一个基于多态的职工管理系统 公司中职工分为三类&#xff1a;普通员工、经理、老板&#xff0c;显示信息时&#xff0c;需要显示职工编号、职工姓名、职工岗位、以及职责 普通员工职责…

Redis在项目实践中的问题解决方案汇总

前言 无论是在开发过程中还是在准备跑路的面试过程中&#xff0c;和Redis相关的话题&#xff0c;难免会涉及到四个特殊场景&#xff1a;缓存穿透、缓存雪崩、缓存击穿以及数据一致性。 虽然在作为服务缓存层的时候Redis确实能极大减少服务端的请求压力&#xff0c;但是如果在…

企业组织管理神器:红海云可视化组织管理功能深度解析

在当前的VUCA时代&#xff0c;企业需要保持敏捷以应对变革和不确定性。组织架构作为承载战略目标的重要工具&#xff0c;如果无法敏捷调整&#xff0c;会直接影响企业战略的成功落地。但组织架构的设计和调整会触及其他业务&#xff0c;包括岗位、编制、人员与汇报关系等信息变…

优先级队列(大根堆与小根堆)

优先级队列&#xff08;大根堆与小根堆&#xff09; 文章目录 优先级队列&#xff08;大根堆与小根堆&#xff09;堆的介绍模拟堆以数组模型为例&#xff0c;创建堆向下调整&#xff08;shiftDown&#xff09;入队&#xff08;push&#xff09;及向上调整&#xff08;shiftUp&a…

java获取文件夹下所有文件名

在进行 Java编程的过程中&#xff0c;我们会经常使用到文件夹下的所有文件名。有时候可能不太熟悉 Java编程的小伙伴们会发现&#xff0c;在代码中没有获取到所有的文件名&#xff0c;那么这个时候我们应该怎么去获取到这些文件呢&#xff1f;在进行 Java编程的过程中&#xff…

《花雕学AI》31:ChatGPT--用关键词/咒语/提示词Prompt激发AI绘画的无限创意!

你有没有想过用AI来画画&#xff1f;ChatGPT是一款基于GPT-3的聊天模式的AI绘画工具&#xff0c;它可以根据你输入的关键词/咒语/提示词Prompt来生成不同风格和主题的画作。Prompt是一些简短的文字&#xff0c;可以用来指导ChatGPT的创作过程。在这篇文章中&#xff0c;我将展示…

2个月快速通过PMP证书的经验分享

01 PMP证书是什么&#xff1f; 指的是项目管理专业人士资格认证。它是由美国项目管理协会&#xff08;Project Management Institute(简称PMI)&#xff09;发起的&#xff0c;严格评估项目管理人员知识技能是否具有高品质的资格认证考试。其目的是为了给项目管理人员提供统一的…

Redis【性能 02】Redis-5.0.14伪集群和Docker集群搭建及延迟和性能测试(均无法提升性能)

伪集群及Docker集群搭建测试流程 1.伪集群搭建1.1 环境1.2 搭建1.2.1 集群配置1.2.2 生成其他5个节点配置1.2.3 启动并验证节点状态1.2.4 创建集群1.2.5 集群信息 1.3 测试 2.Docker集群2.1 环境2.2 搭建2.2.1 创建专用网络2.2.2 生成配置文件2.2.3 容器启动及验证2.2.4 创建集…

NIST SP 800-193: BIOS 平台固件弹性指南

NIST SP 800-147&#xff0c;BIOS 保护指南 ( NIST SP 800-147 [1]、NIST SP 800-147B [2]&#xff09;解决了 BIOS 的保护问题 可从此处免费获得&#xff1a; https://doi.org/10.6028/NIST.SP.800-193 摘要 此文档提供了关于支持平台固件和数据对抗潜在地具有破坏性的攻…