Next.js 应用的内存泄漏的排查和解决

DebugMi 发布于 2024-04-18 09:38编辑于 2024-08-29 03:45阅读:

项目一个 Next.js 应用版本 13.5.4,在日活快过万的时候,观察了一下 grafana 的内存走势,有明显的上升趋势,而且,没有任何释放的意思,很明显的,内存泄漏了

24 小时内存曲线:

2 日内存曲线:

排查过程

首先,在本地启动项目,按生产环境的方式启动尽量模拟生产,我这边用到了 Next.js 的 standalone 模式,所以本地启动步骤有点多。注意 node 后带 --inspect,是为了在 chrome 里调试 nodejs,参考 nodejs 的调试文档

npm run build

cp -r ./public ./.next/standalone && cp -r .next/static .next/standalone/.next && node --inspect ./.next/standalone/server.js

执行后,打开 h5,会发现这里多了个 node 的调试图标,点开他,然后切到 memory tab,可以看到,当前 node 应用的内存情况:

现在需要确定是哪个页面泄漏。这里用到一个比较有名且简单的压测命令行工具wrk,我环境是 Ubuntu,直接 apt 安装就行

sudo apt install wrk

内存监控已经待命,开始对首页进行 DDOS,下面命令意思是,开 10 个线程,400 个 http 连接,保持 30 秒,大概 QPS 为 35

wrk -t10 -c400 -d30s http://localhost:3000

执行后的 30 秒内,每隔 10 秒去监控面板的最左边点一下记录按钮,观察 3 次的内存占用情况:

上图,发现 3 次的内存占用几乎差不多,可以确定,首页没问题,并且不是整个应用的问题,那继续用上面的步骤 DDOS 其他页面

发现问题

在压测其中一个页面的时候,观察到内存不断飙涨,如下图,74->95->115,可以确定就是这个页面了:

点击一个快照,中间上面的过滤选择 comparison 比较,目标是上一个快照。右边的数据 delta 进行降序,delta 意思是增量:

在上表第一名增量的详情里,我一眼就发现了 share-total 字段,因为在这个 h5 页面,使用了ahook的 useRequest 进行了 cacheKey 缓存,这个 cacheKey 就是 share-total,印象比较深

解决问题

然后想到了之前在别的组,好像有同事也发现了 useRequest 的泄漏问题,那看来官方还是没修,既然不修也等不了了,可以基于他封装个 useRequestV2

因为 useRequest 会在 server 阶段执行,在这个阶段把 cacheKey 置空就好,封装代码比较多,下面是部分代码:

const useReqRes = useRequest<TData, TParams>(api, {
  ...options,
  ...getStorageCacheOptions(options),
  cacheKey: isServer() ? undefined : options?.cacheKey,
})

改完后,本地测试,内存不再变化,直接上线

上线一天后,观察 grafana,一切正常,修复后的 24 小时内存趋势:

修复后的 7 天内存趋势:

非常健康,估计 5 年都不需要重启

0