记一次服务端内存泄漏排查之旅(第二篇)

Go语言内存泄漏问题排查总结 背景 我们使用Go语言开发了一个后台服务,在发布测试环境后,发现内存使用量会随着时间的推移持续增加。因此服务的Pod会隔一段时间重启一次,因此,需要排查一下该问题。此文是对排查过程的记录以及排查后的思考总结。 环境准备 本文假设开发机环境中已经安装了go、pprof、graphviz,并且后台服务中已经集成了pprof。 业务中内存泄漏的现象以及排查思路 内存泄漏的现象 我们将服务发布到测试环境中之后,可以从内存监控的看板中看到,内存使用量随着时间的推移会一直增加,而且会一直达到内存设置的限制并且重启Po 阅读详情

目录

      一、事故背景

      二、线上排查

      三、代码分析定位、本地测试验证

      四、问题确认

      五、问题修复

      六、思考启发


一、事故背景

本次线上内存泄漏表现出来(接到报警通知)是在上上周末,当大家都沉浸在周末的闲暇时光的时候

,突然工作群接到运维通知说监控到我们的服务爆出一些500的错误,一时间,小组哗然,大家忙着看各种监控指标是否正常,发现内存大量被占用,居高不下释放不掉,cup持续飙高,接口耗时也非常严重。

基于第一时间恢复线上可用的原则,我们临时对线上服务进行了手动发布部署,先让线上恢复了正常,而且一段时间内都没有问题之后,先暂时记录下诸多个异常点及数据,以便后续排查。

二、线上排查

到了工作日我就基于周末问题点考虑开始着手进行排查、优化,先进行了简单的猜想:内存飙高、释放不掉一般来说有可能是创建了比较大的对象,或者是创建了无用的对象,或者是代码有复杂冗余逻辑、更甚者是有内存泄漏问题。于是查看监控,找到流量较高的TOP接口,先看了下代码逻辑,确实有一些上面的某些问题,就先进行了一波代码逻辑优化,但是,这些代码问题点并不能说服自己,因为即使有这些问题点存在,绝对不会造成线上如此严重的问题呀。

此时,当我再次查看各种监控数据的时候,发现比周末平稳许多,但是比正常的时候看得出还是有一些异常,只是不是特别明显,猜想其实就是跟流量有关系,当流量比较平稳的时候,此时问题肯定表现不出来,看了下实时流量QPS的确不高。

但是,既然周末在某个时间点暴露出来严重的问题,事出必有因,于是开始对线上进行排查,期望能够揪出背后的罪魁祸首。

因为是在工作日,数据异常表象不像是周末那么明显,为了便于排查问题,通过监控我找到了一台当时数据异常表象比其他服务器明显的服务器,登录进控制台,首先使用top命令查看CPU情况

可观测到此时CPU和内存占用,已经表现很明显了。

首先使用jps命令找出应用服务的进程id为1。

jps -l

对于CPU使用率上升,我首先使用了jstack命令查看了jvm线程信息。

jstack  -l  1 > /data/logs/jstack.log

将线程信息dump到jstack.log文件中,使用vi命令打开文件,由于jstack.log文件线程信息比较多,需要我们仔细看线程数量、状态等信息, 通过查看这个文件我发现除了tomcat、redisson、nacos线程池外,其他的线程池基本上都是我们业务中创建的线程池,而且线程池比较多,自定义线程池8个加上hystrix2个,一共使用了10个线程池,这明显创建的太多了,而且通过监控数据来看,很多线程都是处于watiing、time_waiting状态,使用率并不高,白白消耗CPU的调度资源,除此之外,在线程文件中并没有发现其他有用的信息,于是接下来开始进行了jvm垃圾回收、内存数据变化的观测。

使用jstat命令每2秒一次显示进程号为1的java进程垃圾回收统计情况,打印10次,结果如下图

jstat -gcutil 1 2000 10

从这些jvm垃圾回收次数和数据增长数据来看,很明显能够看出Eden区数据增加非常快,并且很快就被晋升到了老年代,老年代增长的也比较快,不断地在触发fullgc,从其他监控数据来看,在周末,每分钟要进行接近30次的gc(ygc&fgc),而且gc时间都比较长,也就是说几乎所有的时间都在进行垃圾回收,然后就会造成用户空间线程阻塞,接口响应大大下降,甚至超时。于是接下来我企图通过其他方式期望找到是哪些接口、创建的什么样的对象造成如此快的对象创建甚至内存释放不掉。

如果直接使用jmap命令只能看jvm各个分区内存使用大小及使用率变化情况,还是看不到更加细粒度的对象行为,于是我使用jmap -histo期望看到对象实例数量及大小的变化情况。

jmap -histo 1 | head -30

使用jmap -histo默认按照占用内存大小降序排序,取TOP30个实例进行查看。

命令执行完成后,得到的是这样的一个jvm实例快照数据,很显然从某个时刻的快照数据并看不出很明显的问题,有可能某个时刻对象就是创建了很多,随即就会被jvm垃圾回收了,也就是说我们需要看的是实时动态的数据变化,于是我手动执行了几次同样的这个命令,结果却让我眼前一亮。

通过不断地执行这个命令,查看动态实时数据变化,我发现两个现象:

①、$1这个内部类一直在递增,并没有被回收而释放掉,其他的对象实例都会在某一瞬间被jvm垃圾回收掉。

②、[Ljava.lang.Object; 这个Object对象变化速率非常快,也就是说相隔很短的时间就会被释放掉,而且,实例数量和占用内存都不小。

至此,通过这些数据现象来看,极有可能发生了内存泄漏,于是,接下来,基于已知的这些问题,带着疑问,看了一下项目源代码。

三、代码分析定位、本地测试验证

我复制了$1这个内部类的类全限定类名,在项目中找到这个类,发现这个内部类是我们接入线程池监控时使用到的一个内部类,用来收集线程池的参数信息。

于是,接下来对StatusExtensionRegister.getInstance().register()进行了代码逻辑查看,发现每次调用register()方法,都会把新创建的内部类add()到StatusExtensionRegister.getInstance()这个类中的集合中去。

而且,跟了下List<StatusExtension> extensions这个集合在源代码中的使用情况,发现并没有在其他地方对这个集合中的元素进行删除,然后本地准备好环境启动服务进行了验证,结果发现确实这个内部类在不断地进行创建,并没有在任何时机回收它。

四、问题确认

从项目源代码来看,这个接入的时机是获取到我们自定义线程池每次执行execute()执行线程任务的时候,只要使用到我们自定义线程池,执行一次,就会创建一个内部类,扔到extensions这个集合中去,而extensions这个集合正因为有类静态属性引用,被GCRoot强引用,所以一直释放不掉,从当前观测的数据来看,我大致计算了一下,这个内部类每小时净增量0.44M,从服务重启到现在时间是98个小时,98*0.44=43.12M,目前服务里面这个内部类整体占用46M,基本上相差不多,这是按照平均计算,3M的差异应该和流量有关,目前这个内部类还在递增,只不过流量很小,增势不明显而已,如果一旦遇到流量高峰,那么项目基本上就扛不住了,至此,从jvm内存数据现象和推算数据来看,已经确定了这个内存泄漏点。

五、问题修复

再次仔细分析了这个线程池监控的接入方式,发现应该在我们自定义线程池创建的时候进行接入、创建这个内部类就行了,进行线程池名称、参数的收集,后续,会有第三方包中的异步线程定时对extensions这个集合中的线程池轮询进行监控,信息上报。

六、思考启发

其实除了内存泄漏,这次线上故障也暴露出来了其他的问题,在这里就不再赘述,我们经历这次事件也做出了几点总结:

①、项目代码仍需要定期review,找出优化点。

②、中间件接入时候需要全面调研,必要时下载源码,搞懂原理。

③、继续进行现有监控体系建设,如果出现任何问题,监控看板会及时发送提醒,为排查类似问题提供线索,快速定位类似问题。

以上是个人的亲身经历及总结经验,个人之见,难免考虑不全,如果大家有更好的建议欢迎大家私信留言。如果对大家有一点点帮助,麻烦动动小手赞个赞也是对我的鼓励和支持。

更多分享请移步至个人公众号,谢谢支持😜😜......

公众号:wenyixicodedog

详解Spring Cloud中Hystrix 线程隔离导致ThreadLocal数据丢失 主要介绍了详解Spring Cloud中Hystrix 线程隔离导致ThreadLocal数据丢失,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧 立即下载

相关推荐

spring-ai学习(四)-MCP

创建一个springai项目1.依赖。

zql1455890112的博客 1386

hystrix /zuul网关拖挂的原因分析created a ThreadLocal with key of type [com.netflix.hystrix.metric.HystrixThr

日志 The web application [ROOT] created a ThreadLocal with key of type [com.netflix.hystrix.metric.HystrixThreadEventStream$1] (value [com.netflix.hystrix.metric.HystrixThreadEventStream$1@60ca88f2]) and a value of type [com.netflix.hystrix.metric.HystrixT.

574

动态数据脱敏技术分析

在当前国内信息安全热潮中,数据脱敏作为数据安全的重要一环得到了业界的认可与重视。早在2012年,数据脱敏首次作为一个单独的魔力象限由Gartner发布,Gartner在2014年又提出了:按照数据使用场景,将数据脱敏分为静态数据脱敏(Static data masking-SDM )与动态数据脱敏(Dynamic data masking-DDM )。 可能有人望文生义,认为动态数据脱敏一定比静态数据脱敏高级。非也非也,静态or动态,取决于脱敏的使用场景,主要是以使用场景为由来选择合适的数据脱敏的模式。 本

美创科技的博客 4677

Hystrix - 内存泄漏排查:Command 对象未释放的常见原因

Hystrix内存泄漏排查:Command对象未释放问题分析 摘要:本文针对微服务架构中Hystrix Command对象未释放导致的内存泄漏问题展开分析。首先解析了Hystrix Command的生命周期,包括创建、执行、完成、缓存和清理等阶段。重点剖析了内存泄漏的三大常见原因:调用方未正确处理Future/Observable对象、Hystrix缓存机制配置不当以及线程池隔离模式下线程泄露问题。文章提供了问题代码示例和解决方案,建议开发者妥善处理异步调用结果、合理配置缓存策略,并注意线程池资源管理。通过

千淘万漉虽辛苦,吹尽狂沙始到金 2万+

【移远EG800K-CN】从AT指令到MQTT实战:4G模块云端通信全解析

本文详细解析移远EG800K-CN 4G模块的AT指令应用与MQTT云端通信实战。从硬件连接到网络配置,再到MQTT协议的数据上报与命令接收,提供了完整的物联网通信解决方案,帮助开发者快速实现设备与云端的稳定数据交互。

o1p2q3r的博客 560

gem5-gpu教程01 部署(实测可跑通)

这将GPGPU-Sim更新为与gem5-gpu兼容的最新版本。此版本是已知可用于gem5 gpu的最新版本。

qq_20388971的博客 1406

hystrix 页面_原创 | JavaWeb中常见的信息泄漏—Hystrix面板

点击上方“蓝字”关注我们了解更多精彩关于Hystrix在微服务的应用场景中,通常会有很多层的服务调用。应用程序有数十个依赖关系,每个依赖关系在某些时候不可避免的会出现问题(例如调用响应时间过长或不可用)。如果一个底层服务出现问题,由于服务与服务之间的依赖性,故障会被向上传播给用户。那么就需要一种机制,当底层服务不可用时,可以阻断故障的传播。在SpringCloud中提供这个机制的组件就是...

weixin_39655981的博客 1272

C++ PCL点云处理实战专栏

工业级点云处理技术学习资源,涵盖电力、建筑、隧道等领域的实战案例。内容分为三阶段:代码原理(算法认知)、动态库(项目验证)和完整代码(定制开发)。

weixin_45196569的博客 1120

记录线上排查内存泄露问题

记录一次云上排查内存泄露的问题,最近监控告警云上有空指针异常报出,于是找到运维查日志定位到具体是哪一行代码抛出的空指针异常,

weixin_44139651的博客 665

华为OD机试新系统真题【迷宫相遇】

华为OD机试 新系统真题【迷宫相遇】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD机试真题【迷宫相遇】多语言题解。

qq_45776114的博客 770

MIKE水动力笔记7_实测数据与模型输出结果的拟合对比

上一博文【MIKE水动力笔记6】主要讲解如何自己制作实测数据的时间序列文件dfs0,而本博文讲解如何进行实测数据与模型输出结果的拟合对比。

晏长街的博客 1万+

小心踩雷,一次Java内存泄漏排查实战

“ 前些日子小组内安排值班,轮流看顾我们的服务,主要做一些报警邮件处理、Bug 排查、运营 issue 处理的事。工作日还好,无论干什么都要上班的,若是轮到周末,那这一天算是毁了。 不知道是公司网络广了就这样还是网络运维组不给力,网络总有问题,不是这边交换机脱网了,就是那边路由器坏了,还偶发地各种超时,而我们灵敏的服务探测服务总能准确地抓住偶现的小问题,给美好的工作加点料。...

8683

RK3588S之CPU--benchmark(一)

本章会基于RK3588S来介绍有关CPU常用的benchmark工具及测试过程

文艺小少年的博客 1499

记一次线上内存泄漏问题的排查过程

近期需要对公司的接口做线上的巡查监控,需要写一个脚本放到服务器上,定时运行脚本监测线上接口是否正常。 测试的接口不是HTTP协议,而是公司基于TCP协议开发的私有协议,因此不能直接用现成的一些接口测试工具,需要自己写代码来调用接口。 由于是私有协议,为了方便各业务项目进行通信,开发部门统一提供了一个TClient的jar包,底层使用了netty框架进行通信。调用方只需要按照协议的格式组装二进制的包...

Testfan_zhou的博客 929

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

一次 Java 内存泄漏的排查

一、由来 前些日子小组内安排值班,轮流看顾我们的服务,主要做一些报警邮件处理、Bug 排查、运营 issue 处理的事。工作日还好,无论干什么都要上班的,若是轮到周末,那这一天算是毁了。 不知道是公司网络广了就这样还是网络运维组不给力,网络总有问题,不是这边交换机脱网了就是那边路由器坏了,还偶发地各种超时,而我们灵敏地服务探测服务总能准确地抓住偶现的小问题,给美好的工作加点料。好几次值班组的小...

测试帮日记 612

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

记一次内存泄漏处理

记一次内存泄漏处理 近期在检查服务器状态时,发现每个Node.js进程占用的内存大小在400-500M之间,根据平时的经验判断是代码中出现了内存泄漏导致,本文就记录这次内存泄漏问题的处理过程。 定位内存泄漏原因过程没有用到什么高难度技术,只是靠经验凭感觉找到的问题代码,简言之就是应用中有一个合成朋友圈分享海报功能,考虑前端canvas兼容性不够好以及该功能使用频次低,所以采用的是服务端合成,就...

沙沙罗曼的专栏 1316

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

分享一次 Java 内存泄漏的排查

点击上方“芋道源码做积极的人,而不是积极废人!源码精品专栏来源:http://t.cn/EIYkz7W由来问题网络问题?问题爆发解决内存泄漏jstat排查分析栈下载堆 dump 文件。使用 MAT 分析 jvm heap分析代码小结由来前些日子小组内安排值班,轮流看顾我们的服务,主要做一些报警邮件处理、Bug 排查、运营 issue 处理的事。工作日还好,无论干什么都要上班的,若是轮到周末,那这...

芋艿V 102

Java 内存泄漏了,怎么排查?

点击关注公众号,Java干货及时送达来源:zhenbianshu.github.io/晚上七点多开始,我就开始不停地收到报警邮件,邮件显示探测的几个接口有超时情况。多数执行栈都在:java.io.BufferedReader.readLine(BufferedReader.java:371) java.io.BufferedReader.readLine(BufferReader.java:389...

Java技术栈,分享最主流的Java技术 2779
上一篇: 二叉树的遍历-前序、中序、后序、层次 Java
下一篇: 一次服务端大面积接口响应时间骤增问题排查
wenyixicodedog
博客等级 码龄8年 87粉丝 116原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值