从零开始搞监控系统(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日志并进行多维度分析。
相关文章
|
11天前
|
消息中间件 数据采集 运维
一份运维监控的终极秘籍!监控不到位,宕机两行泪
【10月更文挑战第25天】监控指标的采集分为基础监控和业务监控。基础监控涉及CPU、内存、磁盘等硬件和网络信息,而业务监控则关注服务运行状态。常见的监控数据采集方法包括日志、JMX、REST、OpenMetrics等。Google SRE提出的四个黄金指标——错误、延迟、流量和饱和度,为监控提供了重要指导。错误监控关注系统和业务错误;延迟监控关注服务响应时间;流量监控关注系统和服务的访问量;饱和度监控关注服务利用率。这些指标有助于及时发现和定位故障。
49 1
|
2月前
|
存储 缓存 前端开发
灵魂拷问-前端到底能做些什么?--性能优化篇
作者最近在尝试对负责的平台进行性能优化,本文整理了些前端性能优化的一些常见策略。
|
2月前
|
NoSQL 程序员 Linux
轻踩一下就崩溃吗——踩内存案例分析
踩内存问题分析成本较高,尤其是低概率问题困难更大。本文详细分析并还原了两个由于动态库全局符号介入机制(it's a feature, not a bug)触发的踩内存案例。
|
6月前
|
存储 NoSQL 编译器
实战总结|抽丝剥茧,记一次神奇的崩溃
本文详细回放了一个崩溃案例的分析过程。回顾了C++多态和类内存布局、pc指针与芯片异常处理、内存屏障的相关知识。
|
消息中间件 监控 算法
JVM技术之旅-线上分析排查问题
JVM技术之旅-线上分析排查问题
303 0
JVM技术之旅-线上分析排查问题
|
监控 数据可视化 Java
JVM技术之旅-带你认识一下JVM调优利器XXFox
JVM技术之旅-带你认识一下JVM调优利器XXFox
356 0
JVM技术之旅-带你认识一下JVM调优利器XXFox
|
缓存 运维 前端开发
面试官:平时工作中有没有做过一些性能优化相关的工作呢?
面试官:平时工作中有没有做过一些性能优化相关的工作呢?
面试官:平时工作中有没有做过一些性能优化相关的工作呢?
|
Java 编译器 索引
Java开发过程中错误集整理
Java开发过程中经常会遇到一些莫名的异常和错误,本文对于常见的依稀问题进行了整理和汇总。
323 1
|
Web App开发 运维 监控
再谈前端性能监控及4个最佳工具分享
对于大多数开发人员而言,监控应用程序的性能并不是一个陌生的概念。在某些情况下,我们必须自己进行一些性能调试。通常,当出现影响用户体验或影响成本的大问题时,就需要去监控应用程序的性能。同时我们也需要话时间去查看应用在不同场景下的表现情况。
842 0
再谈前端性能监控及4个最佳工具分享
|
JSON 监控 小程序
从零开始搞监控系统(5)——小程序监控
  公司目前在线上运行着一款小程序,为了能监控小程序的运行情况,自行开发了一个参数搜集的SDK,名称为 shin.js,放置在 utils 目录中。
从零开始搞监控系统(5)——小程序监控
下一篇
无影云桌面