iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > 其他 >【经验总结 】Node怎么排查内存泄漏?思路分享
  • 315
分享到

【经验总结 】Node怎么排查内存泄漏?思路分享

Node.js前端 2023-05-14 22:05:41 315人浏览 泡泡鱼
摘要

内存泄漏类型内存泄漏主要分为:全局性泄漏局部性泄漏其实不管是全局性内存泄漏还是局部性的内存泄漏,要做的都是尽可能缩小排除范围。全局性内存泄漏全局性内容泄漏出现一般高发于:中间件与组件中,这种类型的内存泄漏排查起来也是最简单的。很遗憾我在 2

内存泄漏类型

内存泄漏主要分为:

  • 全局性泄漏
  • 局部性泄漏

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

全局性内存泄漏

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

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

二分法排查

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

流程流程

  • 先注释一半的代码(减少一半中间件组件、或其它公用逻辑的使用)

  • 随便选择一个接口或新写一个测试接口进行压测

  • 如果出现内存泄漏,那么泄漏点就在当前使用的代码之中,若没有泄漏则泄漏点出现在

  • 然后一直循环往复上述流程大约 20 ~ 60 min 一定可以定位到内存泄漏的详细位置

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 数据

  • 生产启动时 node 添加 --expose-GC,这个参数会向全局注入 gc() 方法,方便手动触发 GC 获取更准确的堆快照数据
  • 这里我加入了两个接口并带上了自己的专属权限,
    • 手动触发 GC
    • 打印堆快照
  • heapdump
    • 项目启动后第一次打印快照数据
    • 内存上涨 100M 后:先触发 GC,再第二次打印堆快照数据
    • 内存接近临界时再次触发 GC 然后打印堆快照

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

  • heapdump时 Node 服务会中断,根据当时服务器内存大小这个时间会在 2 ~ 30min 左右。在生产环境做 heapdump 需要和运维一起制定合理的策略。我在这里是使用了主、备两个 pod, 当主 pod 停掉之后,业务请求会通过负载均衡到备用 pod 由此保障生产业务的正常进行。(这个过程必定是一个与运维密切配合的过程,毕竟 heapdump 玩抽还需要通过他们拿到服务器中堆快照文件)
  • 上述接近临界点打印快照只是一个模糊的描述,如果你试过就知道等非常接近临界点再打印内存快照就打印不出来了。所以接近这个度需要自己把握。
  • 做至少 3 次 heapdump(实际上为了拿到最详细的数据我是做了 5 次)

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

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

  • QPS (每秒请求访问量) ,请求状态,及其访问路径
  • ART (平均接口响应时间) 及其访问数据
  • nodejs 版本
  • Actice Handlers(句柄)
  • Event Loop Lag (事件滞后)
  • 服务进程重启次数
  • CPU 使用率
  • 内存使用:rssheapTotalheapUsedexternalheapAvailableDetail

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

我的分析处理结果

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

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

DX 内存泄漏监控图2.png

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

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

heapdum分析.png

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

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

  • fs.open() 返回的文件句柄
  • net.createServer() 返回的网络服务器句柄
  • dgram.createSocket() 返回的 UDP socket 句柄
  • child_process.spawn() 返回的子进程句柄
  • crypto.createHash() 返回的哈希句柄
  • zlib.createGzip() 返回的压缩句柄

heapdump 分析总结

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

Summary 视图

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

  • TCP
  • Socket
  • EventEmitter
  • global

Comparison 视图

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

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

Comparison视图.png

Containment 视图

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

Containment视图2.png

Statistics 视图

这个图很简单不展开讲了

Statistics视图.png

内存泄漏场景

  • 全局变量:全局变量不会被回收
  • 缓存:使用了内存密集型的第三方库如 lru-cache 存的太多就会导致内存不够用,在 Nodejs 服务中建议使用 Redis 替代 lru-cache
  • 句柄泄漏:调用完系统资源没有释放
  • 事件监听
  • 闭包
  • 循环引用

总结

  • 服务需要接入监控,方便第一时间确定问题类型

  • 判断内存泄漏是全局性的还是局部性的

  • 全局性内存泄漏使用二分法快速排查定位

  • 局部内存泄漏

    • 确定内存泄漏出现时间点,快速定位问题功能
    • 采堆快照数据,至少 3 次
    • 结合监控数据、堆快照数据、与出现泄漏事时间点内的新功能对内存泄漏点进行定位

遇到内存泄漏的问题不要畏惧,多积累内存泄漏问题的排查经验处理经验多了找起来就非常快了。每次解决之后做复盘总结回头再多看看 堆快照 数据利于更快的积累相关经验

其它

  • 压测工具:wrk

以上就是【经验总结 】Node怎么排查内存泄漏?思路分享的详细内容,更多请关注编程网其它相关文章!

--结束END--

本文标题: 【经验总结 】Node怎么排查内存泄漏?思路分享

本文链接: https://www.lsjlt.com/news/206876.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 【经验总结 】Node怎么排查内存泄漏?思路分享
    内存泄漏类型内存泄漏主要分为:全局性泄漏局部性泄漏其实不管是全局性内存泄漏还是局部性的内存泄漏,要做的都是尽可能缩小排除范围。全局性内存泄漏全局性内容泄漏出现一般高发于:中间件与组件中,这种类型的内存泄漏排查起来也是最简单的。很遗憾我在 2...
    99+
    2023-05-14
    Node.js 前端
  • python内存泄漏排查技巧总结
    目录思路一:研究新旧源码及二方库依赖差异思路二:监测新旧版本内存变化差异问题所在进阶思路1.使用objgraph工具2.使用pympler工具首先搞清楚了本次问题的现象: 1. 服务...
    99+
    2024-04-02
  • 怎么排查Javascript内存泄漏
    这篇文章主要讲解了“怎么排查Javascript内存泄漏”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么排查Javascript内存泄漏”吧!如何判断我的应用发生了内存泄漏为了证明螃蟹的听...
    99+
    2023-07-02
  • java内存泄漏怎么排查
    Java内存泄漏是指在程序运行过程中,不再使用的对象仍然占用着内存空间,导致内存无法被回收。以下是一些常见的排查内存泄漏的方法:1....
    99+
    2023-08-31
    java
  • golang内存泄漏怎么排查
    在 Go 语言中,内存泄漏通常是由于不正确地使用或管理指针和引用导致的。以下是一些排查内存泄漏的常用方法:1. 使用 go buil...
    99+
    2023-10-21
    golang
  • linux内存泄漏怎么排查
    要排查Linux中的内存泄漏,可以采取以下步骤: 监视和跟踪内存使用:使用工具如top、htop、vmstat等监视系统的内存使...
    99+
    2024-02-29
    linux
  • linux内存泄漏问题怎么排查
    要排查Linux中的内存泄漏问题,可以按照以下步骤进行:1. 监控内存使用情况:使用工具如top、free或htop等监控系统的实时...
    99+
    2023-10-21
    linux
  • java堆外内存泄漏怎么排查
    在Java中,堆外内存通常是通过直接内存(Direct Memory)分配的。直接内存是一种不受Java堆内存管理的内存分配方式,它...
    99+
    2023-10-27
    java
  • Node怎么最小化堆分配和防止内存泄漏
    这篇文章主要介绍“Node怎么最小化堆分配和防止内存泄漏”,在日常操作中,相信很多人在Node怎么最小化堆分配和防止内存泄漏问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Node怎么最小化堆分配和防止内存泄漏...
    99+
    2023-07-05
  • 怎么在Android中利用LeakCanary对内存泄漏进行排查
    今天就跟大家聊聊有关怎么在Android中利用LeakCanary对内存泄漏进行排查,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。在 build.gralde 里加上依赖, 然后sy...
    99+
    2023-05-31
    android 内存泄漏 leakcanary
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作