Node如何排查内存泄漏

发布时间:2023-01-29 14:17:21 作者:iii
来源:亿速云 阅读:148

这篇文章主要讲解了“Node如何排查内存泄漏”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Node如何排查内存泄漏”吧!

Nodejs 服务端开发的场景中,内存泄漏 绝对是最令人头疼的问题; 但是只要项目一直在开发迭代,那么出现 内存泄漏 的问题绝对不可避免,只是出现的时间早晚而已。所以系统性掌握有效的 内存泄漏 排查方法是一名Nodejs 工程师最基础、最核心的能力。

问题描述

2022 Q4 某天,研发用户群中反馈我们的研发平台不能访问,后台中出现了大量的异常任务未完成。 第一反应就是可能出现了内存泄漏还好服务接入了监控(prometheus + grafana),在grafana 监控面板中发现在 10.00 后内存一直在涨没有下来过出现了明显的数据泄漏。

Node如何排查内存泄漏

说明

Nodejs 中可以调用全局方法 process.memoryUsage() 获取这些数据其中 heapTotalheapUsed 是 V8 堆的使用情况,V8 堆是 Node.js 中 JavaScript 对象存储的地方。而 external 则表示非 V8 堆中分配的内存,例如 C++ 对象。rss 则是进程所有内存的使用量。一般看监控数据的时候重点关注 heapUsed 的指标就行了

内存泄漏类型

内存泄漏主要分为:

其实不管是全局性内存泄漏还是局部性的内存泄漏,要做的都是尽可能缩小排除范围。

全局性内存泄漏

全局性内容泄漏出现一般高发于:中间件组件中,这种类型的内存泄漏排查起来也是最简单的。

很遗憾我在 2022 Q4 中遇到的内存泄漏不属于这个类型,所以还得按照局部性泄漏的思路进行分析。

二分法排查

这种类型我就不讲其它科学的分析方法了,这种情况下我认为使用二分法排查是最快的。

流程流程

2020 年的时候我在做基于 Nuxt SSR 应用时,上线前压测发现应用内存泄漏,判断定为全局性的泄漏之后,采用二分法排查大约花了 30min 就成功定位了问题。
当时泄漏的原因是我们在服务端使用 axios 导致的泄漏,后来统一 axios 相关的全换成 node-fetch 后就解决了,从此换上了 axios PDST 后来绝对不会在 Node 服务中使用 axios

局部性内存泄漏排查

大多数内存泄漏的情况都是局部性的泄漏,泄漏点可能存在与某个中间件、某个接口、某个异步任务中,由于这样的特性它的排查难度也较大。这种情况都会做 heapdump 进行分析。

这里主要讲我这个案例中的思路关于heapdump的详细说明我放在下个段落,

Heap Dump :堆转储, 后面部分都使用 heapdump 表示,做 heapdump 的工具和教程也非常多比如:chrome、vscode、heapdump 这个开源库。我用的 heapdump 库做的网上教程非常多这里不展开了。

局部性内存泄漏排查需要一定的内存泄漏排查经验,每次遇到都把它当成对自己的一次磨砺,这样的经验积累多了以后排查内存泄漏问题会越来越快。

1. 确定内存泄漏出现的时间范围

这一点非常重要,明确了这一点可以大幅度缩小排查范围。
经常会出现这种情况,这个迭代做了A、B、C 三个功能,压测时或上线后出现了内存泄漏。那么就可以直接锁定,内存泄漏发生小这三个新的功能之中。这种情况下就不需要非常麻烦的去生产做 heapdump 我们在本地通过一些工具就可以很轻松的分析定位出内存泄漏点。

由于我们 20年Q4 的一些特殊情况,当我们发现存在内存泄漏的时候已经很难确定内存泄漏初次出现在什么时间点了,只能大概锁定在 1 月的时间内。这一个月中我们又经历了一个大版本迭代,如果一一排查这些功能与接口成本必然非常高。 所以还需要结合更多的数据进行进一步分析

2. 采集 heapdump 数据

采集堆快照数据时需要特别注意的一些点!

3. 结合监控面板的数据进行分析

需要你的应用服务接入监控,我这里应用是使用prometheus + grafana 做的监控, 主要监控服务的以下指标

只有 heapdump 数据是不够的,heapdump 数据非常晦涩,就算在可视化工具的加持下也难以准确定位问题。这个时候我是结合了 grafana 的一些数据一起看。

我的分析处理结果

由于当时的对快照数据丢失了,我这里模拟一下当时的场景。

1、通过 grafana 监控面看看到内存一直在涨一直下不来,但同时我也注意到,服务中的句柄数也在疯涨一直不掉。

Node如何排查内存泄漏

2、这是我回顾了一下出现泄漏的那一个月中新增的功能怀疑可能是在使用 bull 消息队列组件造成的内存泄漏。先去分析了相关应用代码,但并看不出那里写的有问题导致了内存泄漏, 结合 1 中句柄泄漏的问题感觉是在使用 bull 后需要手动的去释放某些资源,在这个时候还不太确定具体原因。

3、然后对 5 次的 heapdunmp 数据进行了分析,数据导入 chrome 对 5 次堆快照进行对比后,发现每次创建队列后 TCP、Socket、EventEmitter 的事件都没有被释放到。到这里基本可以确定是由于对 bull 的使用不规范导致的。在 bull 通常不会频繁创建队列,队列占用的系统资源并不会被自动释放,若有需要,需手动释放。

Node如何排查内存泄漏

4、在调整完代码后重新进行了压测,问题解决。

Tips: Nodejs 中的句柄是一种指针,指向底层系统资源(如文件、网络连接等)。句柄允许 Node.js 程序访问和操作这些资源,而无需直接与底层系统交互。句柄可以是整数或对象,具体取决于 Node.js 库或模块使用的句柄类型。常见句柄:

heapdump 分析总结

通常很多人第一次拿到堆快照数据是懵的,我也是。在看了网上无数的分析技巧结合自身实战后总结了一些比较好用的技巧,一些基础的使用教程这里就不讲了。这里主要讲数据导入 chrome 后如何看图;

Summary 视图

Node如何排查内存泄漏看这个视图的时候一般会先对 Retained Size 进行排查,然后观察其中对象的大小与数量,有经验的工程师,可以快速判断出某些对象数量异常。在这个视图中除了关心自己定义的一些对象之外, 一些容易发生内存泄漏的对象也需要注意如:

Comparison 视图

如果通过 Summary 视图, 不能定位到问题这时我们一般会使用 Comparison 视图。通过这个视图我们能对比两个堆快照中对象个数、与对象占有内存的变化; 通过这些信息我们可以判断在一段时间(某些操作)之后,堆中的对象与内存变化的数值,通过这些数值我们可以找出一些异常的对象。通过这些对象的名称属性或作用可以缩小我们内存泄漏的排查范围。

Comparison 视图中选择两个堆快照,并在它们之间进行比较。您可以查看哪些对象在两个堆快照之间新增,哪些对象在两个堆快照之间减少,以及哪些对象的大小发生了变化。Comparison 视图还允许查看对象之间的关系,以及对象的详细信息,如类型、大小和引用计数。通过这些信息,可以了解哪些对象是导致内存泄漏的原因。

Node如何排查内存泄漏

Containment 视图

显示了对象之间的所有可达的引用关系。每个对象都被表示为一个圆点,并由一条线条连接到它的父对象。通过这种方式可以查看对象之间的层次关系,并了解哪些对象是导致内存泄漏的原因。

Node如何排查内存泄漏

Statistics 视图

这个图很简单不展开讲了

Node如何排查内存泄漏

内存泄漏场景

感谢各位的阅读,以上就是“Node如何排查内存泄漏”的内容了,经过本文的学习后,相信大家对Node如何排查内存泄漏这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

推荐阅读:
  1. vue.js是不是node
  2. 如何切换Node的版本

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

node

上一篇:PHP反序列化入门代码实例分析

下一篇:jquery在div中怎么添加标签

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》