从零开始搞监控系统(4)——内存泄漏

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介:   在将监控日志的服务独立部署后,还是发现CPU会在不特定时间段(例如21~22、23~02等)飙到70%,内存也是一路飙升不会下降,明显是出现了内存泄漏。

  在将监控日志的服务独立部署后,还是发现CPU会在不特定时间段(例如21~22、23~02等)飙到70%,内存也是一路飙升不会下降,明显是出现了内存泄漏。


26.png27.png


  需要进一步做优化,于是开通了阿里云的 Node.js 性能平台


一、Node.js性能平台


  要使用此工具需要在自己的服务器中安装些组件的,具体步骤参考官网说明,公司运维操作起来蛮快的,下图是平台中的数据趋势。


28.png


  点击堆快照,就会生成一个*.heapsnapshot文件,通过该文件就能查看内存的分布和使用情况,点击下图中的转储就能查看分析了。


29.png


  但是我怎么点,每次都是失败,后面找了阿里云的技术人员,他说是因为文件太大,下载的时候总是会断开,无奈,只能在服务器上手动下载,然后在本地Chrome中加载了。


二、分析


  在该平台上下载了堆快照(*.heapsnapshot文件),在Chrome的Memory选项卡中载入,可以看到下图内容。


30.png


1)任务队列(Kue.js)

  翻看其中的几列,发现内存中滞留了很多队列任务的数据,于是锁定内存暴涨与队列有关。

  然后开始查代码,并且在本地做了调试,发现在任务完成后没有将其标记为成功,因为声明的那个改变状态的函数没有被执行。

  只有标记成功的任务才会被自动清除,由于状态没有更新,导致滞留在内存中,从而使得内存一直在涨而不会降。

  一顿操作猛如虎,但是最后发布上去后,内存并没有降下来,依然在增长中,说明不是这个问题。

  在创建队列任务时会打条日志,然后在完成任务后,会再打一条日志,发现一分钟内会创建大约4、5百个任务,但是完成的任务只有200个,甚至更少。

  也就是出队的速度没有入队快,队列来不及处理任务。如此下去的话,就会将任务堆积在一起。

  马上为队列处理的方法加了个并发的参数,再用LoadTest模拟并发,效果非常理想,任务有条不紊地被处理了,于是发布了代码。

  若要结束并发测试,mac电脑可执行命令 kill -USR2 36155,其中 36155 是端口号。


31.png


  但高兴的还是太早,虽然为队列加了并发的设置,但滞留的任务并没有减少,猜想可能是任务中的逻辑阻塞了任务的完成,继续将耗时逻辑注释掉,内存并没有如预期那样降下来。

  再次分析,感觉是上面配置的并发没有生效,很奇怪,查看Kue.js源码也没看出个所以然来。

  只能另辟蹊径了,也就是多创建几种类型,但处理的逻辑是一样的,以此来弥补任务队列的吞吐量。


for (let i = 1; i <= 3; i++) {
  const taskName = "handleMonitor" + i;
  queue.process(taskName, (job, done) => {
    services.common
      .handleMonitor(job.data.monitor)
      .then(() => {
        done();
      })
      .catch((err) => {
        done(err);
      });
  });
}


  查看日志,发现队列的入和出已经平衡,但是内存仍然会升,没有降的趋势。

2)继续分析

  再次观察堆快照,我一度怀疑是 SequelizeKOA 或 Node.js 8.0版本的问题,翻来覆去的查,虽然的确看到了内存泄漏的蛛丝马迹,但仍然没有起色。

  后面将两份堆快照做对比,在查看增长的数据时,发现我请求的 ma.gif 路径中的变量不会释放,存在着一个闭包,八成是这个原因导致内存一直涨。


32.png


  于是仔细查看代码,将最可疑的一句代码注释掉,如下所示,省略了其他逻辑,就放出了关键的那句代码,为外部的 queue 对象反复注册了一个error事件。

import queue from "../util/queue";
router.get("/ma.gif", async (ctx) => {
  queue.on('error', function( err ) {
    logger.trace('handleMonitor queue error', err);
  });
});

  没想到内存一下子平稳了,没有出现暴增的情况。一波多折后发现,原来是自己写的代码不对导致内存的泄漏。


33.png


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
7月前
|
监控 Oracle Java
《深入浅出Java虚拟机 — JVM原理与实战》带你攻克技术盲区,探索各大JVM虚拟机特色 —— JVM故障排除指南(先导篇)
《深入浅出Java虚拟机 — JVM原理与实战》带你攻克技术盲区,探索各大JVM虚拟机特色 —— JVM故障排除指南(先导篇)
127 0
|
Arthas 监控 Java
|
1月前
|
Arthas 监控 Java
JVM进阶调优系列(9)大厂面试官:内存溢出几种?能否现场演示一下?| 面试就那点事
本文介绍了JVM内存溢出(OOM)的四种类型:堆内存、栈内存、元数据区和直接内存溢出。每种类型通过示例代码演示了如何触发OOM,并分析了其原因。文章还提供了如何使用JVM命令工具(如jmap、jhat、GCeasy、Arthas等)分析和定位内存溢出问题的方法。最后,强调了合理设置JVM参数和及时回收内存的重要性。
|
6月前
|
监控 Java 调度
探秘Java虚拟机(JVM)性能调优:技术要点与实战策略
【6月更文挑战第30天】**探索JVM性能调优:**关注堆内存配置(Xms, Xmx, XX:NewRatio, XX:SurvivorRatio),选择适合的垃圾收集器(如Parallel, CMS, G1),利用jstat, jmap等工具诊断,解决Full GC问题,实战中结合MAT分析内存泄露。调优是平衡内存占用、延迟和吞吐量的艺术,借助VisualVM等工具提升系统在高负载下的稳定性与效率。
108 1
|
7月前
|
存储 NoSQL 编译器
实战总结|抽丝剥茧,记一次神奇的崩溃
本文详细回放了一个崩溃案例的分析过程。回顾了C++多态和类内存布局、pc指针与芯片异常处理、内存屏障的相关知识。
|
7月前
|
Arthas Prometheus 监控
JVM工作原理与实战(二十九):监控内存泄漏的工具
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了解决内存溢出的步骤、Top命令、VisualVM、Arthas、Prometheus + Grafana等内容。
470 0
|
7月前
|
监控 Java 数据库连接
开源项目datavines内存泄漏问题分析
开源项目datavines内存泄漏问题分析
134 0
|
监控 算法 Java
后浪,谈谈你对jvm性能调优的理解
后浪,谈谈你对jvm性能调优的理解
173 1
后浪,谈谈你对jvm性能调优的理解
|
监控 数据可视化 Java
JVM技术之旅-带你认识一下JVM调优利器XXFox
JVM技术之旅-带你认识一下JVM调优利器XXFox
365 0
JVM技术之旅-带你认识一下JVM调优利器XXFox
|
缓存 运维 前端开发
面试官:平时工作中有没有做过一些性能优化相关的工作呢?
面试官:平时工作中有没有做过一些性能优化相关的工作呢?
面试官:平时工作中有没有做过一些性能优化相关的工作呢?

热门文章

最新文章